diff options
45 files changed, 1303 insertions, 971 deletions
diff --git a/src/main/cpp/blaze.cc b/src/main/cpp/blaze.cc index d023f6491a..7487c76c90 100644 --- a/src/main/cpp/blaze.cc +++ b/src/main/cpp/blaze.cc @@ -64,6 +64,8 @@ #include "src/main/cpp/util/file.h" #include "src/main/cpp/util/logging.h" #include "src/main/cpp/util/numbers.h" +#include "src/main/cpp/util/path.h" +#include "src/main/cpp/util/path_platform.h" #include "src/main/cpp/util/port.h" #include "src/main/cpp/util/strings.h" #include "src/main/cpp/workspace_layout.h" @@ -412,7 +414,8 @@ static vector<string> GetArgumentArray( result.push_back("-XX:+HeapDumpOnOutOfMemoryError"); string heap_crash_path = globals->options->output_base; - result.push_back("-XX:HeapDumpPath=" + blaze::PathAsJvmFlag(heap_crash_path)); + result.push_back("-XX:HeapDumpPath=" + + blaze_util::PathAsJvmFlag(heap_crash_path)); result.push_back("-Xverify:none"); @@ -442,7 +445,7 @@ static vector<string> GetArgumentArray( bool first = true; for (const auto &it : globals->extracted_binaries) { if (IsSharedLibrary(it)) { - string libpath(blaze::PathAsJvmFlag( + string libpath(blaze_util::PathAsJvmFlag( blaze_util::JoinPath(real_install_dir, blaze_util::Dirname(it)))); // Only add the library path if it's not added yet. if (java_library_paths.find(libpath) == java_library_paths.end()) { @@ -497,14 +500,14 @@ static vector<string> GetArgumentArray( ToString(globals->options->connect_timeout_secs)); result.push_back("--output_user_root=" + - blaze::ConvertPath(globals->options->output_user_root)); + blaze_util::ConvertPath(globals->options->output_user_root)); result.push_back("--install_base=" + - blaze::ConvertPath(globals->options->install_base)); + blaze_util::ConvertPath(globals->options->install_base)); result.push_back("--install_md5=" + globals->install_md5); result.push_back("--output_base=" + - blaze::ConvertPath(globals->options->output_base)); + blaze_util::ConvertPath(globals->options->output_base)); result.push_back("--workspace_directory=" + - blaze::ConvertPath(globals->workspace)); + blaze_util::ConvertPath(globals->workspace)); result.push_back("--default_system_javabase=" + GetSystemJavabase()); if (!globals->options->server_jvm_out.empty()) { @@ -1170,8 +1173,8 @@ static void EnsureCorrectRunningVersion(BlazeServer *server) { string prev_installation; bool ok = blaze_util::ReadDirectorySymlink(installation_path, &prev_installation); - if (!ok || !CompareAbsolutePaths(prev_installation, - globals->options->install_base)) { + if (!ok || !blaze_util::CompareAbsolutePaths( + prev_installation, globals->options->install_base)) { if (server->Connected()) { BAZEL_LOG(INFO) << "Killing running server because it is using another version of " diff --git a/src/main/cpp/blaze_util.cc b/src/main/cpp/blaze_util.cc index d7ab44ca01..10c4e1a38f 100644 --- a/src/main/cpp/blaze_util.cc +++ b/src/main/cpp/blaze_util.cc @@ -43,18 +43,6 @@ const unsigned int kPostShutdownGracePeriodSeconds = 60; const unsigned int kPostKillGracePeriodSeconds = 10; -string MakeAbsolute(const string &p) { - string path = ConvertPath(p); - if (path.empty()) { - return blaze_util::GetCwd(); - } - if (blaze_util::IsDevNull(path.c_str()) || blaze_util::IsAbsolute(path)) { - return path; - } - - return blaze_util::JoinPath(blaze_util::GetCwd(), path); -} - const char* GetUnaryOption(const char *arg, const char *next_arg, const char *key) { diff --git a/src/main/cpp/blaze_util.h b/src/main/cpp/blaze_util.h index e7f8ba1c46..084e8d6653 100644 --- a/src/main/cpp/blaze_util.h +++ b/src/main/cpp/blaze_util.h @@ -30,15 +30,6 @@ namespace blaze { extern const char kServerPidFile[]; -// Returns the given path in absolute form. Does not change paths that are -// already absolute. -// -// If called from working directory "/bar": -// MakeAbsolute("foo") --> "/bar/foo" -// MakeAbsolute("/foo") ---> "/foo" -// MakeAbsolute("C:/foo") ---> "C:/foo" -std::string MakeAbsolute(const std::string &path); - // If 'arg' matches 'key=value', returns address of 'value'. // If it matches 'key' alone, returns address of next_arg. // Returns NULL otherwise. diff --git a/src/main/cpp/blaze_util_linux.cc b/src/main/cpp/blaze_util_linux.cc index 4f01ba833b..dee5463f72 100644 --- a/src/main/cpp/blaze_util_linux.cc +++ b/src/main/cpp/blaze_util_linux.cc @@ -32,6 +32,7 @@ #include "src/main/cpp/util/exit_code.h" #include "src/main/cpp/util/file.h" #include "src/main/cpp/util/logging.h" +#include "src/main/cpp/util/path.h" #include "src/main/cpp/util/port.h" #include "src/main/cpp/util/strings.h" diff --git a/src/main/cpp/blaze_util_platform.h b/src/main/cpp/blaze_util_platform.h index 6de5eb154a..f08aa567e4 100644 --- a/src/main/cpp/blaze_util_platform.h +++ b/src/main/cpp/blaze_util_platform.h @@ -119,16 +119,6 @@ int ExecuteDaemon(const std::string& exe, const std::string& server_dir, BlazeServerStartup** server_startup); -// Convert a path from Bazel internal form to underlying OS form. -// On Unixes this is an identity operation. -// On Windows, Bazel internal form is cygwin path, and underlying OS form -// is Windows path. -std::string ConvertPath(const std::string& path); - -// Converts `path` to a string that's safe to pass as path in a JVM flag. -// See https://github.com/bazelbuild/bazel/issues/2576 -std::string PathAsJvmFlag(const std::string& path); - // A character used to separate paths in a list. extern const char kListSeparator; @@ -137,12 +127,6 @@ extern const char kListSeparator; // Implemented via junctions on Windows. bool SymlinkDirectories(const std::string& target, const std::string& link); -// Compares two absolute paths. Necessary because the same path can have -// multiple different names under msys2: "C:\foo\bar" or "C:/foo/bar" -// (Windows-style) and "/c/foo/bar" (msys2 style). Returns if the paths are -// equal. -bool CompareAbsolutePaths(const std::string& a, const std::string& b); - struct BlazeLock { #if defined(COMPILER_MSVC) || defined(__CYGWIN__) /* HANDLE */ void* handle; diff --git a/src/main/cpp/blaze_util_posix.cc b/src/main/cpp/blaze_util_posix.cc index 4f8d9c766c..156b021529 100644 --- a/src/main/cpp/blaze_util_posix.cc +++ b/src/main/cpp/blaze_util_posix.cc @@ -12,6 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include "src/main/cpp/blaze_util_platform.h" + #define _WITH_DPRINTF #include <dirent.h> #include <errno.h> @@ -36,7 +38,6 @@ #include <cinttypes> #include "src/main/cpp/blaze_util.h" -#include "src/main/cpp/blaze_util_platform.h" #include "src/main/cpp/global_variables.h" #include "src/main/cpp/startup_options.h" #include "src/main/cpp/util/errors.h" @@ -45,6 +46,8 @@ #include "src/main/cpp/util/logging.h" #include "src/main/cpp/util/md5.h" #include "src/main/cpp/util/numbers.h" +#include "src/main/cpp/util/path.h" +#include "src/main/cpp/util/path_platform.h" namespace blaze { @@ -173,10 +176,6 @@ void ExecuteProgram(const string& exe, const vector<string>& args_vector) { execv(exe.c_str(), const_cast<char**>(argv)); } -std::string ConvertPath(const std::string &path) { return path; } - -std::string PathAsJvmFlag(const std::string& path) { return path; } - const char kListSeparator = ':'; bool SymlinkDirectories(const string &target, const string &link) { @@ -403,10 +402,6 @@ int ExecuteDaemon(const string& exe, } } -bool CompareAbsolutePaths(const string& a, const string& b) { - return a == b; -} - string GetHashedBaseDir(const string& root, const string& hashable) { unsigned char buf[blaze_util::Md5Digest::kDigestLength]; blaze_util::Md5Digest digest; diff --git a/src/main/cpp/blaze_util_windows.cc b/src/main/cpp/blaze_util_windows.cc index 565e8876c2..d41a2f4493 100644 --- a/src/main/cpp/blaze_util_windows.cc +++ b/src/main/cpp/blaze_util_windows.cc @@ -12,6 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include "src/main/cpp/blaze_util_platform.h" + #include <fcntl.h> #include <stdarg.h> // va_start, va_end, va_list @@ -33,7 +35,6 @@ #include <vector> #include "src/main/cpp/blaze_util.h" -#include "src/main/cpp/blaze_util_platform.h" #include "src/main/cpp/global_variables.h" #include "src/main/cpp/startup_options.h" #include "src/main/cpp/util/errors.h" @@ -43,6 +44,8 @@ #include "src/main/cpp/util/logging.h" #include "src/main/cpp/util/md5.h" #include "src/main/cpp/util/numbers.h" +#include "src/main/cpp/util/path.h" +#include "src/main/cpp/util/path_platform.h" #include "src/main/cpp/util/strings.h" #include "src/main/native/windows/file.h" #include "src/main/native/windows/util.h" @@ -652,36 +655,6 @@ void ExecuteProgram(const string& exe, const std::vector<string>& args_vector) { const char kListSeparator = ';'; -string PathAsJvmFlag(const string& path) { - string spath; - string error; - if (!blaze_util::AsShortWindowsPath(path, &spath, &error)) { - BAZEL_DIE(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR) - << "PathAsJvmFlag(" << path - << "): AsShortWindowsPath failed: " << error; - } - // Convert backslashes to forward slashes, in order to avoid the JVM parsing - // Windows paths as if they contained escaped characters. - // See https://github.com/bazelbuild/bazel/issues/2576 - std::replace(spath.begin(), spath.end(), '\\', '/'); - return spath; -} - -string ConvertPath(const string& path) { - // The path may not be Windows-style and may not be normalized, so convert it. - wstring wpath; - string error; - if (!blaze_util::AsAbsoluteWindowsPath(path, &wpath, &error)) { - BAZEL_DIE(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR) - << "ConvertPath(" << path - << "): AsAbsoluteWindowsPath failed: " << error; - } - std::transform(wpath.begin(), wpath.end(), wpath.begin(), ::towlower); - return string(blaze_util::WstringToCstring( - blaze_util::RemoveUncPrefixMaybe(wpath.c_str())) - .get()); -} - bool SymlinkDirectories(const string &posix_target, const string &posix_name) { wstring name; wstring target; @@ -708,9 +681,6 @@ bool SymlinkDirectories(const string &posix_target, const string &posix_name) { return true; } -bool CompareAbsolutePaths(const string& a, const string& b) { - return ConvertPath(a) == ConvertPath(b); -} #ifndef STILL_ACTIVE #define STILL_ACTIVE (259) // From MSDN about GetExitCodeProcess. diff --git a/src/main/cpp/option_processor.cc b/src/main/cpp/option_processor.cc index 7df0af7203..a1d7f9d976 100644 --- a/src/main/cpp/option_processor.cc +++ b/src/main/cpp/option_processor.cc @@ -27,6 +27,8 @@ #include "src/main/cpp/blaze_util_platform.h" #include "src/main/cpp/util/file.h" #include "src/main/cpp/util/logging.h" +#include "src/main/cpp/util/path.h" +#include "src/main/cpp/util/path_platform.h" #include "src/main/cpp/util/strings.h" #include "src/main/cpp/workspace_layout.h" @@ -136,7 +138,7 @@ blaze_exit_code::ExitCode OptionProcessor::FindUserBlazerc( "." + parsed_startup_options_->GetLowercaseProductName() + "rc"; if (cmd_line_rc_file != nullptr) { - string rcFile = MakeAbsolute(cmd_line_rc_file); + string rcFile = blaze_util::MakeAbsolute(cmd_line_rc_file); if (!blaze_util::CanReadFile(rcFile)) { blaze_util::StringPrintf(error, "Error: Unable to read %s file '%s'.", rc_basename.c_str(), @@ -424,7 +426,7 @@ static void PreprocessEnvString(string* env_str) { } else if (name == "TMP") { // A valid Windows path "c:/foo" is also a valid Unix path list of // ["c", "/foo"] so must use ConvertPath here. See GitHub issue #1684. - env_str->assign("TMP=" + ConvertPath(env_str->substr(pos + 1))); + env_str->assign("TMP=" + blaze_util::ConvertPath(env_str->substr(pos + 1))); } } @@ -477,7 +479,7 @@ std::vector<std::string> OptionProcessor::GetBlazercAndEnvCommandArgs( // from multiple places. if (rcfile_indexes.find(source_path) != rcfile_indexes.end()) continue; - result.push_back("--rc_source=" + blaze::ConvertPath(source_path)); + result.push_back("--rc_source=" + blaze_util::ConvertPath(source_path)); rcfile_indexes[source_path] = cur_index; cur_index++; } @@ -503,7 +505,7 @@ std::vector<std::string> OptionProcessor::GetBlazercAndEnvCommandArgs( for (const string& env_var : env) { result.push_back("--client_env=" + env_var); } - result.push_back("--client_cwd=" + blaze::ConvertPath(cwd)); + result.push_back("--client_cwd=" + blaze_util::ConvertPath(cwd)); return result; } diff --git a/src/main/cpp/startup_options.cc b/src/main/cpp/startup_options.cc index 5ccec1d635..3699d40498 100644 --- a/src/main/cpp/startup_options.cc +++ b/src/main/cpp/startup_options.cc @@ -25,6 +25,8 @@ #include "src/main/cpp/util/file.h" #include "src/main/cpp/util/logging.h" #include "src/main/cpp/util/numbers.h" +#include "src/main/cpp/util/path.h" +#include "src/main/cpp/util/path_platform.h" #include "src/main/cpp/util/strings.h" #include "src/main/cpp/workspace_layout.h" @@ -93,7 +95,7 @@ StartupOptions::StartupOptions(const string &product_name, original_startup_options_(std::vector<RcStartupFlag>()) { bool testing = !blaze::GetEnv("TEST_TMPDIR").empty(); if (testing) { - output_root = MakeAbsolute(blaze::GetEnv("TEST_TMPDIR")); + output_root = blaze_util::MakeAbsolute(blaze::GetEnv("TEST_TMPDIR")); max_idle_secs = 15; BAZEL_LOG(USER) << "$TEST_TMPDIR defined: output root default is '" << output_root << "' and max_idle_secs default is '" @@ -187,19 +189,19 @@ blaze_exit_code::ExitCode StartupOptions::ProcessArg( const char* value = NULL; if ((value = GetUnaryOption(arg, next_arg, "--output_base")) != NULL) { - output_base = MakeAbsolute(value); + output_base = blaze_util::MakeAbsolute(value); option_sources["output_base"] = rcfile; } else if ((value = GetUnaryOption(arg, next_arg, "--install_base")) != NULL) { - install_base = MakeAbsolute(value); + install_base = blaze_util::MakeAbsolute(value); option_sources["install_base"] = rcfile; } else if ((value = GetUnaryOption(arg, next_arg, "--output_user_root")) != NULL) { - output_user_root = MakeAbsolute(value); + output_user_root = blaze_util::MakeAbsolute(value); option_sources["output_user_root"] = rcfile; } else if ((value = GetUnaryOption(arg, next_arg, "--server_jvm_out")) != NULL) { - server_jvm_out = MakeAbsolute(value); + server_jvm_out = blaze_util::MakeAbsolute(value); option_sources["server_jvm_out"] = rcfile; } else if (GetNullaryOption(arg, "--deep_execroot")) { deep_execroot = true; @@ -221,7 +223,7 @@ blaze_exit_code::ExitCode StartupOptions::ProcessArg( "--host_javabase")) != NULL) { // TODO(bazel-team): Consider examining the javabase and re-execing in case // of architecture mismatch. - host_javabase = MakeAbsolute(value); + host_javabase = blaze_util::MakeAbsolute(value); option_sources["host_javabase"] = rcfile; } else if ((value = GetUnaryOption(arg, next_arg, "--host_jvm_args")) != NULL) { @@ -486,8 +488,8 @@ void StartupOptions::AddJVMArgumentSuffix(const string &real_install_dir, const string &jar_path, std::vector<string> *result) const { result->push_back("-jar"); - result->push_back( - blaze::PathAsJvmFlag(blaze_util::JoinPath(real_install_dir, jar_path))); + result->push_back(blaze_util::PathAsJvmFlag( + blaze_util::JoinPath(real_install_dir, jar_path))); } blaze_exit_code::ExitCode StartupOptions::AddJVMArguments( @@ -502,7 +504,7 @@ void StartupOptions::AddJVMLoggingArguments(std::vector<string> *result) const { const string propFile = blaze_util::JoinPath(output_base, "javalog.properties"); string java_log( - blaze::PathAsJvmFlag(blaze_util::JoinPath(output_base, "java.log"))); + blaze_util::PathAsJvmFlag(blaze_util::JoinPath(output_base, "java.log"))); if (!blaze_util::WriteFile("handlers=java.util.logging.FileHandler\n" ".level=INFO\n" "java.util.logging.FileHandler.level=INFO\n" diff --git a/src/main/cpp/util/BUILD b/src/main/cpp/util/BUILD index 254b6f8f1f..6f53b4d590 100644 --- a/src/main/cpp/util/BUILD +++ b/src/main/cpp/util/BUILD @@ -15,13 +15,15 @@ cc_library( "file_platform.h", "md5.h", "numbers.h", + "path.h", + "path_platform.h", "port.h", ], visibility = ["//visibility:public"], deps = [ ":blaze_exit_code", ":errors", - ":file", + ":filesystem", ":md5", ":numbers", ":port", @@ -30,18 +32,25 @@ cc_library( ) cc_library( - name = "file", - srcs = ["file.cc"] + select({ + name = "filesystem", + srcs = [ + "file.cc", + "path.cc", + ] + select({ "//src/conditions:windows": [ "file_windows.cc", + "path_windows.cc", ], "//conditions:default": [ "file_posix.cc", + "path_posix.cc", ], }), hdrs = [ "file.h", "file_platform.h", + "path.h", + "path_platform.h", ], visibility = [ ":ijar", @@ -108,7 +117,7 @@ cc_library( visibility = ["//visibility:public"], deps = [ ":blaze_exit_code", - ":file", + ":filesystem", ":logging", ], ) diff --git a/src/main/cpp/util/file.cc b/src/main/cpp/util/file.cc index 3eb614c0dc..041d7798dc 100644 --- a/src/main/cpp/util/file.cc +++ b/src/main/cpp/util/file.cc @@ -11,6 +11,9 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. + +#include "src/main/cpp/util/file.h" + #include <limits.h> // PATH_MAX #include <algorithm> @@ -19,7 +22,7 @@ #include "src/main/cpp/util/errors.h" #include "src/main/cpp/util/exit_code.h" -#include "src/main/cpp/util/file.h" +#include "src/main/cpp/util/path.h" #include "src/main/cpp/util/strings.h" namespace blaze_util { @@ -85,39 +88,6 @@ bool WriteFile(const std::string &content, const std::string &filename, return WriteFile(content.c_str(), content.size(), filename, perm); } -string Dirname(const string &path) { - return SplitPath(path).first; -} - -string Basename(const string &path) { - return SplitPath(path).second; -} - -string JoinPath(const string &path1, const string &path2) { - if (path1.empty()) { - // "" + "/bar" - return path2; - } - - if (path1[path1.size() - 1] == '/') { - if (path2.find('/') == 0) { - // foo/ + /bar - return path1 + path2.substr(1); - } else { - // foo/ + bar - return path1 + path2; - } - } else { - if (path2.find('/') == 0) { - // foo + /bar - return path1 + path2; - } else { - // foo + bar - return path1 + "/" + path2; - } - } -} - class DirectoryTreeWalker : public DirectoryEntryConsumer { public: DirectoryTreeWalker(vector<string> *files, diff --git a/src/main/cpp/util/file.h b/src/main/cpp/util/file.h index 4bc165110e..235ec87527 100644 --- a/src/main/cpp/util/file.h +++ b/src/main/cpp/util/file.h @@ -63,17 +63,6 @@ bool ReadFrom(file_handle_type handle, void *data, size_t size); bool WriteFile(const std::string &content, const std::string &filename, unsigned int perm = 0644); -// Returns the part of the path before the final "/". If there is a single -// leading "/" in the path, the result will be the leading "/". If there is -// no "/" in the path, the result is the empty prefix of the input (i.e., ""). -std::string Dirname(const std::string &path); - -// Returns the part of the path after the final "/". If there is no -// "/" in the path, the result is the same as the input. -std::string Basename(const std::string &path); - -std::string JoinPath(const std::string &path1, const std::string &path2); - // Lists all files in `path` and all of its subdirectories. // // Does not follow symlinks / junctions. diff --git a/src/main/cpp/util/file_platform.h b/src/main/cpp/util/file_platform.h index 5b96133d3a..ac4fc3ab00 100644 --- a/src/main/cpp/util/file_platform.h +++ b/src/main/cpp/util/file_platform.h @@ -50,9 +50,6 @@ class IFileMtime { // Creates a platform-specific implementation of `IFileMtime`. IFileMtime *CreateFileMtime(); -// Split a path to dirname and basename parts. -std::pair<std::string, std::string> SplitPath(const std::string &path); - #if defined(COMPILER_MSVC) || defined(__CYGWIN__) // We cannot include <windows.h> because it #defines many symbols that conflict // with our function names, e.g. GetUserName, SendMessage. @@ -162,17 +159,9 @@ bool CanExecuteFile(const std::string &path); // Follows symlinks/junctions. bool CanAccessDirectory(const std::string &path); -bool IsDevNull(const char *path); - // Returns true if `path` refers to a directory or a symlink/junction to one. bool IsDirectory(const std::string& path); -// Returns true if `path` is the root directory or a Windows drive root. -bool IsRootDirectory(const std::string &path); - -// Returns true if `path` is absolute. -bool IsAbsolute(const std::string &path); - // Calls fsync() on the file (or directory) specified in 'file_path'. // pdie() if syncing fails. void SyncFile(const std::string& path); @@ -211,20 +200,7 @@ void ForEachDirectoryEntry(const std::string &path, DirectoryEntryConsumer *consume); #if defined(COMPILER_MSVC) || defined(__CYGWIN__) -const wchar_t *RemoveUncPrefixMaybe(const wchar_t *ptr); - -bool AsWindowsPath(const std::string &path, std::string *result, - std::string *error); - -bool AsAbsoluteWindowsPath(const std::string &path, std::wstring *wpath, - std::string *error); - -// Same as `AsWindowsPath`, but returns a lowercase 8dot3 style shortened path. -// Result will never have a UNC prefix, nor a trailing "/" or "\". -// Works also for non-existent paths; shortens as much of them as it can. -// Also works for non-existent drives. -bool AsShortWindowsPath(const std::string &path, std::string *result, - std::string *error); +std::wstring GetCwdW(); #endif // defined(COMPILER_MSVC) || defined(__CYGWIN__) } // namespace blaze_util diff --git a/src/main/cpp/util/file_posix.cc b/src/main/cpp/util/file_posix.cc index 5136df0655..df05b54a45 100644 --- a/src/main/cpp/util/file_posix.cc +++ b/src/main/cpp/util/file_posix.cc @@ -12,6 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. +#include "src/main/cpp/util/file_platform.h" + #include <dirent.h> // DIR, dirent, opendir, closedir #include <errno.h> #include <fcntl.h> // O_RDONLY @@ -29,6 +31,8 @@ #include "src/main/cpp/util/exit_code.h" #include "src/main/cpp/util/file.h" #include "src/main/cpp/util/logging.h" +#include "src/main/cpp/util/path.h" +#include "src/main/cpp/util/path_platform.h" #include "src/main/cpp/util/strings.h" namespace blaze_util { @@ -178,18 +182,6 @@ IPipe* CreatePipe() { return new PosixPipe(fd[0], fd[1]); } -pair<string, string> SplitPath(const string &path) { - size_t pos = path.rfind('/'); - - // Handle the case with no '/' in 'path'. - if (pos == string::npos) return std::make_pair("", path); - - // Handle the case with a single leading '/' in 'path'. - if (pos == 0) return std::make_pair(string(path, 0, 1), string(path, 1)); - - return std::make_pair(string(path, 0, pos), string(path, pos + 1)); -} - int ReadFromHandle(file_handle_type fd, void *data, size_t size, int *error) { int result = read(fd, data, size); if (error != nullptr) { @@ -299,10 +291,6 @@ static bool CanAccess(const string &path, bool read, bool write, bool exec) { return access(path.c_str(), mode) == 0; } -bool IsDevNull(const char *path) { - return path != NULL && *path != 0 && strncmp("/dev/null\0", path, 10) == 0; -} - bool CanReadFile(const std::string &path) { return !IsDirectory(path) && CanAccess(path, true, false, false); } @@ -320,12 +308,6 @@ bool IsDirectory(const string& path) { return stat(path.c_str(), &buf) == 0 && S_ISDIR(buf.st_mode); } -bool IsRootDirectory(const string &path) { - return path.size() == 1 && path[0] == '/'; -} - -bool IsAbsolute(const string &path) { return !path.empty() && path[0] == '/'; } - void SyncFile(const string& path) { const char* file_path = path.c_str(); int fd = open(file_path, O_RDONLY); diff --git a/src/main/cpp/util/file_windows.cc b/src/main/cpp/util/file_windows.cc index 39160c9c22..537852eb70 100644 --- a/src/main/cpp/util/file_windows.cc +++ b/src/main/cpp/util/file_windows.cc @@ -24,6 +24,8 @@ #include "src/main/cpp/util/exit_code.h" #include "src/main/cpp/util/file.h" #include "src/main/cpp/util/logging.h" +#include "src/main/cpp/util/path.h" +#include "src/main/cpp/util/path_platform.h" #include "src/main/cpp/util/strings.h" #include "src/main/native/windows/file.h" #include "src/main/native/windows/util.h" @@ -40,11 +42,7 @@ using bazel::windows::GetLongPath; using bazel::windows::HasUncPrefix; using bazel::windows::OpenDirectory; -// Returns the current working directory as a Windows path. -// The result may have a UNC prefix. -static unique_ptr<WCHAR[]> GetCwdW(); -static char GetCurrentDrive(); // Returns true if `path` refers to a directory or (non-dangling) junction. // `path` must be a normalized Windows path, with UNC prefix (and absolute) if @@ -57,64 +55,15 @@ static bool IsDirectoryW(const wstring& path); // necessary. static bool UnlinkPathW(const wstring& path); -static bool IsRootDirectoryW(const wstring& path); - static bool MakeDirectoriesW(const wstring& path); static bool CanReadFileW(const wstring& path); -// Returns a normalized form of the input `path`. -// -// `path` must be a relative or absolute Windows path, it may use "/" instead of -// "\" but must not be a Unix-style (MSYS) path. -// The result won't have a UNC prefix, even if `path` did. -// -// Normalization means removing "." references, resolving ".." references, and -// deduplicating "/" characters while converting them to "\". -// For example if `path` is "foo/../bar/.//qux", the result is "bar\qux". -// -// Uplevel references that cannot go any higher in the directory tree are simply -// ignored, e.g. "c:/.." is normalized to "c:\" and "../../foo" is normalized to -// "foo". -// -// Visible for testing, would be static otherwise. -string NormalizeWindowsPath(string path); - -template <typename char_type> -struct CharTraits { - static bool IsAlpha(char_type ch); -}; - -template <> -struct CharTraits<char> { - static bool IsAlpha(char ch) { return isalpha(ch); } -}; - -template <> -struct CharTraits<wchar_t> { - static bool IsAlpha(wchar_t ch) { return iswalpha(ch); } -}; - template <typename char_type> static bool IsPathSeparator(char_type ch) { return ch == '/' || ch == '\\'; } -template <typename char_type> -static bool HasDriveSpecifierPrefix(const char_type* ch) { - return CharTraits<char_type>::IsAlpha(ch[0]) && ch[1] == ':'; -} - -static void AddUncPrefixMaybe(wstring* path, size_t max_path = MAX_PATH) { - if (path->size() >= max_path && !HasUncPrefix(path->c_str())) { - *path = wstring(L"\\\\?\\") + *path; - } -} - -const wchar_t* RemoveUncPrefixMaybe(const wchar_t* ptr) { - return ptr + (HasUncPrefix(ptr) ? 4 : 0); -} - class WindowsPipe : public IPipe { public: WindowsPipe(const HANDLE& read_handle, const HANDLE& write_handle) @@ -300,239 +249,6 @@ FILETIME WindowsFileMtime::GetFuture(WORD years) { IFileMtime* CreateFileMtime() { return new WindowsFileMtime(); } -// Checks if the path is absolute and/or is a root path. -// -// If `must_be_root` is true, then in addition to being absolute, the path must -// also be just the root part, no other components, e.g. "c:\" is both absolute -// and root, but "c:\foo" is just absolute. -template <typename char_type> -static bool IsRootOrAbsolute(const basic_string<char_type>& path, - bool must_be_root) { - // An absolute path is one that starts with "/", "\", "c:/", "c:\", - // "\\?\c:\", or rarely "\??\c:\" or "\\.\c:\". - // - // It is unclear whether the UNC prefix is just "\\?\" or is "\??\" also - // valid (in some cases it seems to be, though MSDN doesn't mention it). - return - // path is (or starts with) "/" or "\" - ((must_be_root ? path.size() == 1 : !path.empty()) && - IsPathSeparator(path[0])) || - // path is (or starts with) "c:/" or "c:\" or similar - ((must_be_root ? path.size() == 3 : path.size() >= 3) && - HasDriveSpecifierPrefix(path.c_str()) && IsPathSeparator(path[2])) || - // path is (or starts with) "\\?\c:\" or "\??\c:\" or similar - ((must_be_root ? path.size() == 7 : path.size() >= 7) && - HasUncPrefix(path.c_str()) && - HasDriveSpecifierPrefix(path.c_str() + 4) && IsPathSeparator(path[6])); -} - -template <typename char_type> -static pair<basic_string<char_type>, basic_string<char_type> > SplitPathImpl( - const basic_string<char_type>& path) { - if (path.empty()) { - return std::make_pair(basic_string<char_type>(), basic_string<char_type>()); - } - - size_t pos = path.size() - 1; - for (auto it = path.crbegin(); it != path.crend(); ++it, --pos) { - if (IsPathSeparator(*it)) { - if ((pos == 2 || pos == 6) && - IsRootOrAbsolute(path.substr(0, pos + 1), /* must_be_root */ true)) { - // Windows path, top-level directory, e.g. "c:\foo", - // result is ("c:\", "foo"). - // Or UNC path, top-level directory, e.g. "\\?\c:\foo" - // result is ("\\?\c:\", "foo"). - return std::make_pair( - // Include the "/" or "\" in the drive specifier. - path.substr(0, pos + 1), path.substr(pos + 1)); - } else { - // Windows path (neither top-level nor drive root), Unix path, or - // relative path. - return std::make_pair( - // If the only "/" is the leading one, then that shall be the first - // pair element, otherwise the substring up to the rightmost "/". - pos == 0 ? path.substr(0, 1) : path.substr(0, pos), - // If the rightmost "/" is the tail, then the second pair element - // should be empty. - pos == path.size() - 1 ? basic_string<char_type>() - : path.substr(pos + 1)); - } - } - } - // Handle the case with no '/' or '\' in `path`. - return std::make_pair(basic_string<char_type>(), path); -} - -pair<string, string> SplitPath(const string& path) { - return SplitPathImpl(path); -} - -pair<wstring, wstring> SplitPathW(const wstring& path) { - return SplitPathImpl(path); -} - -bool AsWindowsPath(const string& path, string* result, string* error) { - if (path.empty()) { - result->clear(); - return true; - } - if (IsDevNull(path.c_str())) { - result->assign("NUL"); - return true; - } - if (HasUncPrefix(path.c_str())) { - // Path has "\\?\" prefix --> assume it's already Windows-style. - *result = path.c_str(); - return true; - } - if (IsPathSeparator(path[0]) && path.size() > 1 && IsPathSeparator(path[1])) { - // Unsupported path: "\\" or "\\server\path", or some degenerate form of - // these, such as "//foo". - if (error) { - *error = "network paths are unsupported"; - } - return false; - } - if (HasDriveSpecifierPrefix(path.c_str()) && - (path.size() < 3 || !IsPathSeparator(path[2]))) { - // Unsupported path: "c:" or "c:foo" - if (error) { - *error = "working-directory relative paths are unsupported"; - } - return false; - } - - string mutable_path = path; - if (path[0] == '/') { - if (error) { - *error = "Unix-style paths are unsupported"; - } - return false; - } - - if (path[0] == '\\') { - // This is an absolute Windows path on the current drive, e.g. "\foo\bar". - mutable_path = string(1, GetCurrentDrive()) + ":" + path; - } // otherwise this is a relative path, or absolute Windows path. - - result->assign(NormalizeWindowsPath(mutable_path)); - return true; -} - -// Converts a UTF8-encoded `path` to a normalized, widechar Windows path. -// -// Returns true if conversion succeeded and sets the contents of `result` to it. -// -// The input `path` may be an absolute or relative Windows path. -// -// The returned path is normalized (see NormalizeWindowsPath). -// -// If `path` had a "\\?\" prefix then the function assumes it's already Windows -// style and converts it to wstring without any alterations. -// Otherwise `path` is normalized and converted to a Windows path and the result -// won't have a "\\?\" prefix even if it's longer than MAX_PATH (adding the -// prefix is the caller's responsibility). -// -// The method recognizes current-drive-relative Windows paths ("\foo") turning -// them into absolute paths ("c:\foo"). -bool AsWindowsPath(const string& path, wstring* result, string* error) { - string normalized_win_path; - if (!AsWindowsPath(path, &normalized_win_path, error)) { - return false; - } - - result->assign(CstringToWstring(normalized_win_path.c_str()).get()); - return true; -} - -bool AsAbsoluteWindowsPath(const string& path, wstring* result, string* error) { - if (path.empty()) { - result->clear(); - return true; - } - if (IsDevNull(path.c_str())) { - result->assign(L"NUL"); - return true; - } - if (!AsWindowsPath(path, result, error)) { - return false; - } - if (!IsRootOrAbsolute(*result, /* must_be_root */ false)) { - *result = wstring(GetCwdW().get()) + L"\\" + *result; - } - if (!HasUncPrefix(result->c_str())) { - *result = wstring(L"\\\\?\\") + *result; - } - return true; -} - -bool AsShortWindowsPath(const string& path, string* result, string* error) { - if (IsDevNull(path.c_str())) { - result->assign("NUL"); - return true; - } - - result->clear(); - wstring wpath; - wstring wsuffix; - if (!AsAbsoluteWindowsPath(path, &wpath, error)) { - return false; - } - DWORD size = ::GetShortPathNameW(wpath.c_str(), nullptr, 0); - if (size == 0) { - // GetShortPathNameW can fail if `wpath` does not exist. This is expected - // when we are about to create a file at that path, so instead of failing, - // walk up in the path until we find a prefix that exists and can be - // shortened, or is a root directory. Save the non-existent tail in - // `wsuffix`, we'll add it back later. - std::vector<wstring> segments; - while (size == 0 && !IsRootDirectoryW(wpath)) { - pair<wstring, wstring> split = SplitPathW(wpath); - wpath = split.first; - segments.push_back(split.second); - size = ::GetShortPathNameW(wpath.c_str(), nullptr, 0); - } - - // Join all segments. - std::wostringstream builder; - bool first = true; - for (auto it = segments.crbegin(); it != segments.crend(); ++it) { - if (!first || !IsRootDirectoryW(wpath)) { - builder << L'\\' << *it; - } else { - builder << *it; - } - first = false; - } - wsuffix = builder.str(); - } - - wstring wresult; - if (IsRootDirectoryW(wpath)) { - // Strip the UNC prefix from `wpath`, and the leading "\" from `wsuffix`. - wresult = wstring(RemoveUncPrefixMaybe(wpath.c_str())) + wsuffix; - } else { - unique_ptr<WCHAR[]> wshort( - new WCHAR[size]); // size includes null-terminator - if (size - 1 != ::GetShortPathNameW(wpath.c_str(), wshort.get(), size)) { - if (error) { - string last_error = GetLastErrorString(); - std::stringstream msg; - msg << "AsShortWindowsPath(" << path << "): GetShortPathNameW(" - << blaze_util::WstringToString(wpath) << ") failed: " << last_error; - *error = msg.str(); - } - return false; - } - // GetShortPathNameW may preserve the UNC prefix in the result, so strip it. - wresult = wstring(RemoveUncPrefixMaybe(wshort.get())) + wsuffix; - } - - result->assign(WstringToCstring(wresult.c_str()).get()); - ToLower(result); - return true; -} - static bool OpenFileForReading(const string& filename, HANDLE* result) { if (filename.empty()) { return false; @@ -1067,14 +783,6 @@ bool CanAccessDirectory(const std::string& path) { return true; } -bool IsDevNull(const char* path) { - return path != NULL && *path != 0 && - (strncmp("/dev/null\0", path, 10) == 0 || - ((path[0] == 'N' || path[0] == 'n') && - (path[1] == 'U' || path[1] == 'u') && - (path[2] == 'L' || path[2] == 'l') && path[3] == 0)); -} - static bool IsDirectoryW(const wstring& path) { DWORD attrs = ::GetFileAttributesW(path.c_str()); return (attrs != INVALID_FILE_ATTRIBUTES) && @@ -1097,21 +805,11 @@ bool IsDirectory(const string& path) { return IsDirectoryW(wpath); } -bool IsRootDirectory(const string& path) { - return IsRootOrAbsolute(path, true); -} - -bool IsAbsolute(const string& path) { return IsRootOrAbsolute(path, false); } - void SyncFile(const string& path) { // No-op on Windows native; unsupported by Cygwin. // fsync always fails on Cygwin with "Permission denied" for some reason. } -static bool IsRootDirectoryW(const wstring& path) { - return IsRootOrAbsolute(path, true); -} - static bool MakeDirectoriesW(const wstring& path) { if (path.empty()) { return false; @@ -1150,7 +848,7 @@ bool MakeDirectories(const string& path, unsigned int mode) { return MakeDirectoriesW(wpath); } -static unique_ptr<WCHAR[]> GetCwdW() { +std::wstring GetCwdW() { DWORD len = ::GetCurrentDirectoryW(0, nullptr); unique_ptr<WCHAR[]> cwd(new WCHAR[len]); if (!::GetCurrentDirectoryW(len, cwd.get())) { @@ -1160,18 +858,12 @@ static unique_ptr<WCHAR[]> GetCwdW() { for (WCHAR* p = cwd.get(); *p != 0; ++p) { *p = towlower(*p); } - return std::move(cwd); + return std::wstring(cwd.get()); } string GetCwd() { - return string(WstringToCstring(RemoveUncPrefixMaybe(GetCwdW().get())).get()); -} - -static char GetCurrentDrive() { - unique_ptr<wchar_t[]> cwd = GetCwdW(); - wchar_t wdrive = RemoveUncPrefixMaybe(cwd.get())[0]; - wchar_t offset = wdrive >= L'A' && wdrive <= L'Z' ? L'A' : L'a'; - return 'a' + wdrive - offset; + return string( + WstringToCstring(RemoveUncPrefixMaybe(GetCwdW().c_str())).get()); } bool ChangeDirectory(const string& path) { @@ -1227,69 +919,4 @@ void ForEachDirectoryEntry(const string &path, ::FindClose(handle); } -string NormalizeWindowsPath(string path) { - if (path.empty()) { - return ""; - } - if (path[0] == '/') { - // This is an absolute MSYS path, error out. - BAZEL_DIE(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR) - << "NormalizeWindowsPath(" << path << "): expected a Windows path"; - } - if (path.size() >= 4 && HasUncPrefix(path.c_str())) { - path = path.substr(4); - } - - static const string dot("."); - static const string dotdot(".."); - - std::vector<string> segments; - int segment_start = -1; - // Find the path segments in `path` (separated by "/"). - for (int i = 0;; ++i) { - if (!IsPathSeparator(path[i]) && path[i] != '\0') { - // The current character does not end a segment, so start one unless it's - // already started. - if (segment_start < 0) { - segment_start = i; - } - } else if (segment_start >= 0 && i > segment_start) { - // The current character is "/" or "\0", so this ends a segment. - // Add that to `segments` if there's anything to add; handle "." and "..". - string segment(path, segment_start, i - segment_start); - segment_start = -1; - if (segment == dotdot) { - if (!segments.empty() && - !HasDriveSpecifierPrefix(segments[0].c_str())) { - segments.pop_back(); - } - } else if (segment != dot) { - segments.push_back(segment); - } - } - if (path[i] == '\0') { - break; - } - } - - // Handle the case when `path` is just a drive specifier (or some degenerate - // form of it, e.g. "c:\.."). - if (segments.size() == 1 && segments[0].size() == 2 && - HasDriveSpecifierPrefix(segments[0].c_str())) { - return segments[0] + '\\'; - } - - // Join all segments. - bool first = true; - std::ostringstream result; - for (const auto& s : segments) { - if (!first) { - result << '\\'; - } - first = false; - result << s; - } - return result.str(); -} - } // namespace blaze_util diff --git a/src/main/cpp/util/path.cc b/src/main/cpp/util/path.cc new file mode 100644 index 0000000000..efa10b81d4 --- /dev/null +++ b/src/main/cpp/util/path.cc @@ -0,0 +1,64 @@ +// Copyright 2018 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "src/main/cpp/util/path.h" + +#include "src/main/cpp/util/file_platform.h" +#include "src/main/cpp/util/path_platform.h" + +namespace blaze_util { + +std::string Dirname(const std::string &path) { return SplitPath(path).first; } + +std::string Basename(const std::string &path) { return SplitPath(path).second; } + +std::string JoinPath(const std::string &path1, const std::string &path2) { + if (path1.empty()) { + // "" + "/bar" + return path2; + } + + if (path1[path1.size() - 1] == '/') { + if (path2.find('/') == 0) { + // foo/ + /bar + return path1 + path2.substr(1); + } else { + // foo/ + bar + return path1 + path2; + } + } else { + if (path2.find('/') == 0) { + // foo + /bar + return path1 + path2; + } else { + // foo + bar + return path1 + "/" + path2; + } + } +} + +std::string MakeAbsolute(const std::string &path) { + std::string converted_path = ConvertPath(path); + if (converted_path.empty()) { + return GetCwd(); + } + if (IsDevNull(converted_path.c_str()) || + blaze_util::IsAbsolute(converted_path)) { + return converted_path; + } + + return JoinPath(blaze_util::GetCwd(), converted_path); +} + +} // namespace blaze_util diff --git a/src/main/cpp/util/path.h b/src/main/cpp/util/path.h new file mode 100644 index 0000000000..38e735b7af --- /dev/null +++ b/src/main/cpp/util/path.h @@ -0,0 +1,43 @@ +// Copyright 2018 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#ifndef BAZEL_SRC_MAIN_CPP_UTIL_PATH_H_ +#define BAZEL_SRC_MAIN_CPP_UTIL_PATH_H_ + +#include <string> + +namespace blaze_util { + +// Returns the part of the path before the final "/". If there is a single +// leading "/" in the path, the result will be the leading "/". If there is +// no "/" in the path, the result is the empty prefix of the input (i.e., ""). +std::string Dirname(const std::string &path); + +// Returns the part of the path after the final "/". If there is no +// "/" in the path, the result is the same as the input. +std::string Basename(const std::string &path); + +std::string JoinPath(const std::string &path1, const std::string &path2); + +// Returns the given path in absolute form. Does not change paths that are +// already absolute. +// +// If called from working directory "/bar": +// MakeAbsolute("foo") --> "/bar/foo" +// MakeAbsolute("/foo") ---> "/foo" +// MakeAbsolute("C:/foo") ---> "C:/foo" +std::string MakeAbsolute(const std::string &path); + +} // namespace blaze_util + +#endif // BAZEL_SRC_MAIN_CPP_UTIL_PATH_H_ diff --git a/src/main/cpp/util/path_platform.h b/src/main/cpp/util/path_platform.h new file mode 100644 index 0000000000..abb25dcb75 --- /dev/null +++ b/src/main/cpp/util/path_platform.h @@ -0,0 +1,119 @@ +// Copyright 2018 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#ifndef BAZEL_SRC_MAIN_CPP_UTIL_PATH_PLATFORM_H_ +#define BAZEL_SRC_MAIN_CPP_UTIL_PATH_PLATFORM_H_ + +#include <string> + +namespace blaze_util { + +// Convert a path from Bazel internal form to underlying OS form. +// On Unixes this is an identity operation. +// On Windows, Bazel internal form is cygwin path, and underlying OS form +// is Windows path. +std::string ConvertPath(const std::string &path); + +// Converts `path` to a string that's safe to pass as path in a JVM flag. +// See https://github.com/bazelbuild/bazel/issues/2576 +std::string PathAsJvmFlag(const std::string &path); + +// Compares two absolute paths. Necessary because the same path can have +// multiple different names under msys2: "C:\foo\bar" or "C:/foo/bar" +// (Windows-style) and "/c/foo/bar" (msys2 style). Returns if the paths are +// equal. +bool CompareAbsolutePaths(const std::string &a, const std::string &b); + +// Split a path to dirname and basename parts. +std::pair<std::string, std::string> SplitPath(const std::string &path); + +bool IsDevNull(const char *path); + +// Returns true if `path` is the root directory or a Windows drive root. +bool IsRootDirectory(const std::string &path); + +// Returns true if `path` is absolute. +bool IsAbsolute(const std::string &path); + +// TODO(bazel-team) consider changing the path(_platform) header split to be a +// path.h and path_windows.h split, which would make it clearer what functions +// are included by an import statement. The downside to this gain in clarity +// is that this would add more complexity to the implementation file(s)? of +// path.h, which would have to have the platform-specific implementations. +#if defined(COMPILER_MSVC) || defined(__CYGWIN__) +const wchar_t *RemoveUncPrefixMaybe(const wchar_t *ptr); +void AddUncPrefixMaybe(std::wstring *path); + +std::pair<std::wstring, std::wstring> SplitPathW(const std::wstring &path); + +bool IsRootDirectoryW(const std::wstring &path); + +bool AsWindowsPath(const std::string &path, std::string *result, + std::string *error); + +// Returns a normalized form of the input `path`. +// +// `path` must be a relative or absolute Windows path, it may use "/" instead of +// "\" but must not be a Unix-style (MSYS) path. +// The result won't have a UNC prefix, even if `path` did. +// +// Normalization means removing "." references, resolving ".." references, and +// deduplicating "/" characters while converting them to "\". +// For example if `path` is "foo/../bar/.//qux", the result is "bar\qux". +// +// Uplevel references that cannot go any higher in the directory tree are simply +// ignored, e.g. "c:/.." is normalized to "c:\" and "../../foo" is normalized to +// "foo". +// +// Visible for testing, would be static otherwise. +std::string NormalizeWindowsPath(std::string path); + +// Converts a UTF8-encoded `path` to a normalized, widechar Windows path. +// +// Returns true if conversion succeeded and sets the contents of `result` to it. +// +// The input `path` may be an absolute or relative Windows path. +// +// The returned path is normalized (see NormalizeWindowsPath). +// +// If `path` had a "\\?\" prefix then the function assumes it's already Windows +// style and converts it to wstring without any alterations. +// Otherwise `path` is normalized and converted to a Windows path and the result +// won't have a "\\?\" prefix even if it's longer than MAX_PATH (adding the +// prefix is the caller's responsibility). +// +// The method recognizes current-drive-relative Windows paths ("\foo") turning +// them into absolute paths ("c:\foo"). +bool AsWindowsPath(const std::string &path, std::wstring *result, + std::string *error); + +bool AsAbsoluteWindowsPath(const std::string &path, std::wstring *wpath, + std::string *error); + +// Same as `AsWindowsPath`, but returns a lowercase 8dot3 style shortened path. +// Result will never have a UNC prefix, nor a trailing "/" or "\". +// Works also for non-existent paths; shortens as much of them as it can. +// Also works for non-existent drives. +bool AsShortWindowsPath(const std::string &path, std::string *result, + std::string *error); + +template <typename char_type> +bool IsPathSeparator(char_type ch); + +template <typename char_type> +bool HasDriveSpecifierPrefix(const char_type *ch); + +#endif // defined(COMPILER_MSVC) || defined(__CYGWIN__) +} // namespace blaze_util + +#endif // BAZEL_SRC_MAIN_CPP_UTIL_PATH_PLATFORM_H_ diff --git a/src/main/cpp/util/path_posix.cc b/src/main/cpp/util/path_posix.cc new file mode 100644 index 0000000000..bbeffca30c --- /dev/null +++ b/src/main/cpp/util/path_posix.cc @@ -0,0 +1,60 @@ +// Copyright 2018 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "src/main/cpp/util/path_platform.h" + +#include <limits.h> // PATH_MAX + +#include <string.h> // strncmp +#include <unistd.h> // access, open, close, fsync +#include "src/main/cpp/util/errors.h" +#include "src/main/cpp/util/exit_code.h" +#include "src/main/cpp/util/logging.h" + +namespace blaze_util { + +std::string ConvertPath(const std::string &path) { return path; } + +std::string PathAsJvmFlag(const std::string &path) { return path; } + +bool CompareAbsolutePaths(const std::string &a, const std::string &b) { + return a == b; +} + +std::pair<std::string, std::string> SplitPath(const std::string &path) { + size_t pos = path.rfind('/'); + + // Handle the case with no '/' in 'path'. + if (pos == std::string::npos) return std::make_pair("", path); + + // Handle the case with a single leading '/' in 'path'. + if (pos == 0) + return std::make_pair(std::string(path, 0, 1), std::string(path, 1)); + + return std::make_pair(std::string(path, 0, pos), std::string(path, pos + 1)); +} + +bool IsDevNull(const char *path) { + return path != NULL && *path != 0 && strncmp("/dev/null\0", path, 10) == 0; +} + +bool IsRootDirectory(const std::string &path) { + return path.size() == 1 && path[0] == '/'; +} + +bool IsAbsolute(const std::string &path) { + return !path.empty() && path[0] == '/'; +} + +} // namespace blaze_util diff --git a/src/main/cpp/util/path_windows.cc b/src/main/cpp/util/path_windows.cc new file mode 100644 index 0000000000..d3756c71bf --- /dev/null +++ b/src/main/cpp/util/path_windows.cc @@ -0,0 +1,420 @@ +// Copyright 2018 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "src/main/cpp/util/path_platform.h" + +#include <wchar.h> // wcslen +#include <windows.h> + +#include <algorithm> +#include <memory> // unique_ptr +#include <sstream> +#include <vector> + +#include "src/main/cpp/util/errors.h" +#include "src/main/cpp/util/exit_code.h" +#include "src/main/cpp/util/file_platform.h" +#include "src/main/cpp/util/logging.h" +#include "src/main/cpp/util/strings.h" +#include "src/main/native/windows/file.h" + +namespace blaze_util { + +using bazel::windows::HasUncPrefix; + +static char GetCurrentDrive(); + +template <typename char_type> +struct CharTraits { + static bool IsAlpha(char_type ch); +}; + +template <> +struct CharTraits<char> { + static bool IsAlpha(char ch) { return isalpha(ch); } +}; + +template <> +struct CharTraits<wchar_t> { + static bool IsAlpha(wchar_t ch) { return iswalpha(ch); } +}; + +template <typename char_type> +static bool IsPathSeparator(char_type ch) { + return ch == '/' || ch == '\\'; +} + +template <typename char_type> +static bool HasDriveSpecifierPrefix(const char_type* ch) { + return CharTraits<char_type>::IsAlpha(ch[0]) && ch[1] == ':'; +} + +std::string ConvertPath(const std::string& path) { + // The path may not be Windows-style and may not be normalized, so convert it. + std::wstring wpath; + std::string error; + if (!AsAbsoluteWindowsPath(path, &wpath, &error)) { + BAZEL_DIE(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR) + << "ConvertPath(" << path + << "): AsAbsoluteWindowsPath failed: " << error; + } + std::transform(wpath.begin(), wpath.end(), wpath.begin(), ::towlower); + return std::string( + WstringToCstring(RemoveUncPrefixMaybe(wpath.c_str())).get()); +} + +bool CompareAbsolutePaths(const std::string& a, const std::string& b) { + return ConvertPath(a) == ConvertPath(b); +} + +std::string PathAsJvmFlag(const std::string& path) { + std::string spath; + std::string error; + if (!AsShortWindowsPath(path, &spath, &error)) { + BAZEL_DIE(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR) + << "PathAsJvmFlag(" << path + << "): AsShortWindowsPath failed: " << error; + } + // Convert backslashes to forward slashes, in order to avoid the JVM parsing + // Windows paths as if they contained escaped characters. + // See https://github.com/bazelbuild/bazel/issues/2576 + std::replace(spath.begin(), spath.end(), '\\', '/'); + return spath; +} + +void AddUncPrefixMaybe(std::wstring* path) { + if (path->size() >= MAX_PATH && !HasUncPrefix(path->c_str())) { + *path = std::wstring(L"\\\\?\\") + *path; + } +} + +const wchar_t* RemoveUncPrefixMaybe(const wchar_t* ptr) { + return ptr + (HasUncPrefix(ptr) ? 4 : 0); +} + +// Checks if the path is absolute and/or is a root path. +// +// If `must_be_root` is true, then in addition to being absolute, the path must +// also be just the root part, no other components, e.g. "c:\" is both absolute +// and root, but "c:\foo" is just absolute. +template <typename char_type> +static bool IsRootOrAbsolute(const std::basic_string<char_type>& path, + bool must_be_root) { + // An absolute path is one that starts with "/", "\", "c:/", "c:\", + // "\\?\c:\", or rarely "\??\c:\" or "\\.\c:\". + // + // It is unclear whether the UNC prefix is just "\\?\" or is "\??\" also + // valid (in some cases it seems to be, though MSDN doesn't mention it). + return + // path is (or starts with) "/" or "\" + ((must_be_root ? path.size() == 1 : !path.empty()) && + IsPathSeparator(path[0])) || + // path is (or starts with) "c:/" or "c:\" or similar + ((must_be_root ? path.size() == 3 : path.size() >= 3) && + HasDriveSpecifierPrefix(path.c_str()) && IsPathSeparator(path[2])) || + // path is (or starts with) "\\?\c:\" or "\??\c:\" or similar + ((must_be_root ? path.size() == 7 : path.size() >= 7) && + HasUncPrefix(path.c_str()) && + HasDriveSpecifierPrefix(path.c_str() + 4) && IsPathSeparator(path[6])); +} + +template <typename char_type> +static std::pair<std::basic_string<char_type>, std::basic_string<char_type> > +SplitPathImpl(const std::basic_string<char_type>& path) { + if (path.empty()) { + return std::make_pair(std::basic_string<char_type>(), + std::basic_string<char_type>()); + } + + size_t pos = path.size() - 1; + for (auto it = path.crbegin(); it != path.crend(); ++it, --pos) { + if (IsPathSeparator(*it)) { + if ((pos == 2 || pos == 6) && + IsRootOrAbsolute(path.substr(0, pos + 1), /* must_be_root */ true)) { + // Windows path, top-level directory, e.g. "c:\foo", + // result is ("c:\", "foo"). + // Or UNC path, top-level directory, e.g. "\\?\c:\foo" + // result is ("\\?\c:\", "foo"). + return std::make_pair( + // Include the "/" or "\" in the drive specifier. + path.substr(0, pos + 1), path.substr(pos + 1)); + } else { + // Windows path (neither top-level nor drive root), Unix path, or + // relative path. + return std::make_pair( + // If the only "/" is the leading one, then that shall be the first + // pair element, otherwise the substring up to the rightmost "/". + pos == 0 ? path.substr(0, 1) : path.substr(0, pos), + // If the rightmost "/" is the tail, then the second pair element + // should be empty. + pos == path.size() - 1 ? std::basic_string<char_type>() + : path.substr(pos + 1)); + } + } + } + // Handle the case with no '/' or '\' in `path`. + return std::make_pair(std::basic_string<char_type>(), path); +} + +std::pair<std::string, std::string> SplitPath(const std::string& path) { + return SplitPathImpl(path); +} + +std::pair<std::wstring, std::wstring> SplitPathW(const std::wstring& path) { + return SplitPathImpl(path); +} + +bool AsWindowsPath(const std::string& path, std::string* result, + std::string* error) { + if (path.empty()) { + result->clear(); + return true; + } + if (IsDevNull(path.c_str())) { + result->assign("NUL"); + return true; + } + if (HasUncPrefix(path.c_str())) { + // Path has "\\?\" prefix --> assume it's already Windows-style. + *result = path.c_str(); + return true; + } + if (IsPathSeparator(path[0]) && path.size() > 1 && IsPathSeparator(path[1])) { + // Unsupported path: "\\" or "\\server\path", or some degenerate form of + // these, such as "//foo". + if (error) { + *error = "network paths are unsupported"; + } + return false; + } + if (HasDriveSpecifierPrefix(path.c_str()) && + (path.size() < 3 || !IsPathSeparator(path[2]))) { + // Unsupported path: "c:" or "c:foo" + if (error) { + *error = "working-directory relative paths are unsupported"; + } + return false; + } + + std::string mutable_path = path; + if (path[0] == '/') { + if (error) { + *error = "Unix-style paths are unsupported"; + } + return false; + } + + if (path[0] == '\\') { + // This is an absolute Windows path on the current drive, e.g. "\foo\bar". + mutable_path = std::string(1, GetCurrentDrive()) + ":" + path; + } // otherwise this is a relative path, or absolute Windows path. + + result->assign(NormalizeWindowsPath(mutable_path)); + return true; +} + +bool AsWindowsPath(const std::string& path, std::wstring* result, + std::string* error) { + std::string normalized_win_path; + if (!AsWindowsPath(path, &normalized_win_path, error)) { + return false; + } + + result->assign(CstringToWstring(normalized_win_path.c_str()).get()); + return true; +} + +bool AsAbsoluteWindowsPath(const std::string& path, std::wstring* result, + std::string* error) { + if (path.empty()) { + result->clear(); + return true; + } + if (IsDevNull(path.c_str())) { + result->assign(L"NUL"); + return true; + } + if (!AsWindowsPath(path, result, error)) { + return false; + } + if (!IsRootOrAbsolute(*result, /* must_be_root */ false)) { + *result = GetCwdW() + L"\\" + *result; + } + if (!HasUncPrefix(result->c_str())) { + *result = std::wstring(L"\\\\?\\") + *result; + } + return true; +} + +bool AsShortWindowsPath(const std::string& path, std::string* result, + std::string* error) { + if (IsDevNull(path.c_str())) { + result->assign("NUL"); + return true; + } + + result->clear(); + std::wstring wpath; + std::wstring wsuffix; + if (!AsAbsoluteWindowsPath(path, &wpath, error)) { + return false; + } + DWORD size = ::GetShortPathNameW(wpath.c_str(), nullptr, 0); + if (size == 0) { + // GetShortPathNameW can fail if `wpath` does not exist. This is expected + // when we are about to create a file at that path, so instead of failing, + // walk up in the path until we find a prefix that exists and can be + // shortened, or is a root directory. Save the non-existent tail in + // `wsuffix`, we'll add it back later. + std::vector<std::wstring> segments; + while (size == 0 && !IsRootDirectoryW(wpath)) { + std::pair<std::wstring, std::wstring> split = SplitPathW(wpath); + wpath = split.first; + segments.push_back(split.second); + size = ::GetShortPathNameW(wpath.c_str(), nullptr, 0); + } + + // Join all segments. + std::wostringstream builder; + bool first = true; + for (auto it = segments.crbegin(); it != segments.crend(); ++it) { + if (!first || !IsRootDirectoryW(wpath)) { + builder << L'\\' << *it; + } else { + builder << *it; + } + first = false; + } + wsuffix = builder.str(); + } + + std::wstring wresult; + if (IsRootDirectoryW(wpath)) { + // Strip the UNC prefix from `wpath`, and the leading "\" from `wsuffix`. + wresult = std::wstring(RemoveUncPrefixMaybe(wpath.c_str())) + wsuffix; + } else { + std::unique_ptr<WCHAR[]> wshort( + new WCHAR[size]); // size includes null-terminator + if (size - 1 != ::GetShortPathNameW(wpath.c_str(), wshort.get(), size)) { + if (error) { + std::string last_error = GetLastErrorString(); + std::stringstream msg; + msg << "AsShortWindowsPath(" << path << "): GetShortPathNameW(" + << WstringToString(wpath) << ") failed: " << last_error; + *error = msg.str(); + } + return false; + } + // GetShortPathNameW may preserve the UNC prefix in the result, so strip it. + wresult = std::wstring(RemoveUncPrefixMaybe(wshort.get())) + wsuffix; + } + + result->assign(WstringToCstring(wresult.c_str()).get()); + ToLower(result); + return true; +} + +bool IsDevNull(const char* path) { + return path != NULL && *path != 0 && + (strncmp("/dev/null\0", path, 10) == 0 || + ((path[0] == 'N' || path[0] == 'n') && + (path[1] == 'U' || path[1] == 'u') && + (path[2] == 'L' || path[2] == 'l') && path[3] == 0)); +} + +bool IsRootDirectory(const std::string& path) { + return IsRootOrAbsolute(path, true); +} + +bool IsAbsolute(const std::string& path) { + return IsRootOrAbsolute(path, false); +} + +bool IsRootDirectoryW(const std::wstring& path) { + return IsRootOrAbsolute(path, true); +} + +static char GetCurrentDrive() { + std::wstring cwd = GetCwdW(); + wchar_t wdrive = RemoveUncPrefixMaybe(cwd.c_str())[0]; + wchar_t offset = wdrive >= L'A' && wdrive <= L'Z' ? L'A' : L'a'; + return 'a' + wdrive - offset; +} + +std::string NormalizeWindowsPath(std::string path) { + if (path.empty()) { + return ""; + } + if (path[0] == '/') { + // This is an absolute MSYS path, error out. + BAZEL_DIE(blaze_exit_code::LOCAL_ENVIRONMENTAL_ERROR) + << "NormalizeWindowsPath(" << path << "): expected a Windows path"; + } + if (path.size() >= 4 && HasUncPrefix(path.c_str())) { + path = path.substr(4); + } + + static const std::string dot("."); + static const std::string dotdot(".."); + + std::vector<std::string> segments; + int segment_start = -1; + // Find the path segments in `path` (separated by "/"). + for (int i = 0;; ++i) { + if (!IsPathSeparator(path[i]) && path[i] != '\0') { + // The current character does not end a segment, so start one unless it's + // already started. + if (segment_start < 0) { + segment_start = i; + } + } else if (segment_start >= 0 && i > segment_start) { + // The current character is "/" or "\0", so this ends a segment. + // Add that to `segments` if there's anything to add; handle "." and "..". + std::string segment(path, segment_start, i - segment_start); + segment_start = -1; + if (segment == dotdot) { + if (!segments.empty() && + !HasDriveSpecifierPrefix(segments[0].c_str())) { + segments.pop_back(); + } + } else if (segment != dot) { + segments.push_back(segment); + } + } + if (path[i] == '\0') { + break; + } + } + + // Handle the case when `path` is just a drive specifier (or some degenerate + // form of it, e.g. "c:\.."). + if (segments.size() == 1 && segments[0].size() == 2 && + HasDriveSpecifierPrefix(segments[0].c_str())) { + return segments[0] + '\\'; + } + + // Join all segments. + bool first = true; + std::ostringstream result; + for (const auto& s : segments) { + if (!first) { + result << '\\'; + } + first = false; + result << s; + } + return result.str(); +} + +} // namespace blaze_util diff --git a/src/main/cpp/workspace_layout.cc b/src/main/cpp/workspace_layout.cc index 64f4a6c06d..b1d3ff2fe7 100644 --- a/src/main/cpp/workspace_layout.cc +++ b/src/main/cpp/workspace_layout.cc @@ -19,6 +19,8 @@ #include "src/main/cpp/blaze_util_platform.h" #include "src/main/cpp/util/file.h" #include "src/main/cpp/util/file_platform.h" +#include "src/main/cpp/util/path.h" +#include "src/main/cpp/util/path_platform.h" namespace blaze { diff --git a/src/test/cpp/blaze_util_test.cc b/src/test/cpp/blaze_util_test.cc index 15963b6b5a..03b43c0587 100644 --- a/src/test/cpp/blaze_util_test.cc +++ b/src/test/cpp/blaze_util_test.cc @@ -211,20 +211,4 @@ TEST_F(BlazeUtilTest, TestSearchUnarySkipsAfterDashDashWithoutEquals) { "--flag")); } -TEST_F(BlazeUtilTest, MakeAbsolute) { -#if defined(WIN32) - EXPECT_EQ(MakeAbsolute("C:\\foo\\bar"), "C:\\foo\\bar"); - EXPECT_EQ(MakeAbsolute("C:/foo/bar"), "C:\\foo\\bar"); - EXPECT_EQ(MakeAbsolute("C:\\foo\\bar\\"), "C:\\foo\\bar\\"); - EXPECT_EQ(MakeAbsolute("C:/foo/bar/"), "C:\\foo\\bar\\"); - EXPECT_EQ(MakeAbsolute("foo"), blaze_util::GetCwd() + "\\foo"); -#else - EXPECT_EQ(MakeAbsolute("/foo/bar"), "/foo/bar"); - EXPECT_EQ(MakeAbsolute("/foo/bar/"), "/foo/bar/"); - EXPECT_EQ(MakeAbsolute("foo"), blaze_util::GetCwd() + "/foo"); -#endif - EXPECT_EQ(MakeAbsolute(std::string()), blaze_util::GetCwd()); - EXPECT_EQ(MakeAbsolute("/dev/null"), "/dev/null"); -} - } // namespace blaze diff --git a/src/test/cpp/blaze_util_windows_test.cc b/src/test/cpp/blaze_util_windows_test.cc index 2ac596957d..f577b48ca5 100644 --- a/src/test/cpp/blaze_util_windows_test.cc +++ b/src/test/cpp/blaze_util_windows_test.cc @@ -155,27 +155,4 @@ TEST(BlazeUtilWindowsTest, TestUnsetEnv) { ASSERT_ENVVAR_UNSET(long_key.c_str()); } -TEST(BlazeUtilWindowsTest, ConvertPathTest) { - EXPECT_EQ("c:\\foo", ConvertPath("C:\\FOO")); - EXPECT_EQ("c:\\", ConvertPath("c:/")); - EXPECT_EQ("c:\\foo\\bar", ConvertPath("c:/../foo\\BAR\\.\\")); - EXPECT_EQ("nul", MakeAbsolute("NUL")); - EXPECT_EQ("nul", MakeAbsolute("nul")); - EXPECT_EQ("nul", MakeAbsolute("/dev/null")); -} - -TEST(BlazeUtilWindowsTest, TestMakeAbsolute) { - EXPECT_EQ("c:\\foo\\bar", MakeAbsolute("C:\\foo\\BAR")); - EXPECT_EQ("c:\\foo\\bar", MakeAbsolute("C:/foo/bar")); - EXPECT_EQ("c:\\foo\\bar", MakeAbsolute("C:\\foo\\bar\\")); - EXPECT_EQ("c:\\foo\\bar", MakeAbsolute("C:/foo/bar/")); - EXPECT_EQ(blaze_util::AsLower(blaze_util::GetCwd()) + "\\foo", - MakeAbsolute("foo")); - EXPECT_EQ("nul", MakeAbsolute("NUL")); - EXPECT_EQ("nul", MakeAbsolute("Nul")); - EXPECT_EQ("nul", MakeAbsolute("nul")); - EXPECT_EQ(blaze_util::AsLower(blaze_util::GetCwd()), MakeAbsolute("")); - EXPECT_EQ("nul", MakeAbsolute("/dev/null")); -} - } // namespace blaze diff --git a/src/test/cpp/option_processor_test.cc b/src/test/cpp/option_processor_test.cc index 01e2805665..10e55cf055 100644 --- a/src/test/cpp/option_processor_test.cc +++ b/src/test/cpp/option_processor_test.cc @@ -20,6 +20,7 @@ #include "src/main/cpp/option_processor-internal.h" #include "src/main/cpp/util/file.h" #include "src/main/cpp/util/file_platform.h" +#include "src/main/cpp/util/path.h" #include "src/main/cpp/workspace_layout.h" #include "googletest/include/gtest/gtest.h" diff --git a/src/test/cpp/rc_file_test.cc b/src/test/cpp/rc_file_test.cc index 5900db1cd1..a534778f20 100644 --- a/src/test/cpp/rc_file_test.cc +++ b/src/test/cpp/rc_file_test.cc @@ -21,6 +21,7 @@ #include "src/main/cpp/rc_file.h" #include "src/main/cpp/util/file.h" #include "src/main/cpp/util/file_platform.h" +#include "src/main/cpp/util/path.h" #include "src/main/cpp/workspace_layout.h" #include "googlemock/include/gmock/gmock.h" #include "googletest/include/gtest/gtest.h" diff --git a/src/test/cpp/rc_options_test.cc b/src/test/cpp/rc_options_test.cc index 3a3ebf3c0d..58251afe9a 100644 --- a/src/test/cpp/rc_options_test.cc +++ b/src/test/cpp/rc_options_test.cc @@ -19,6 +19,7 @@ #include "src/main/cpp/option_processor.h" #include "src/main/cpp/util/file.h" #include "src/main/cpp/util/file_platform.h" +#include "src/main/cpp/util/path.h" #include "src/main/cpp/util/strings.h" #include "src/main/cpp/workspace_layout.h" #include "googletest/include/gtest/gtest.h" diff --git a/src/test/cpp/util/BUILD b/src/test/cpp/util/BUILD index 5dcb04adfb..455994f3d9 100644 --- a/src/test/cpp/util/BUILD +++ b/src/test/cpp/util/BUILD @@ -31,7 +31,31 @@ cc_test( }), deps = [ ":test_util", - "//src/main/cpp/util:file", + "//src/main/cpp/util:filesystem", + "@com_google_googletest//:gtest_main", + ] + select({ + "//src/conditions:windows": [ + ":windows_test_util", + "//src/main/native/windows:lib-file", + ], + "//conditions:default": [], + }), +) + +cc_test( + name = "path_test", + size = "small", + srcs = select({ + "//src/conditions:windows": [ + "path_windows_test.cc", + ], + "//conditions:default": [ + "path_posix_test.cc", + ], + }), + deps = [ + ":test_util", + "//src/main/cpp/util:filesystem", "@com_google_googletest//:gtest_main", ] + select({ "//src/conditions:windows": [ @@ -48,7 +72,7 @@ cc_test( deps = [ "//src/main/cpp:blaze_util", "//src/main/cpp/util:bazel_log_handler", - "//src/main/cpp/util:file", + "//src/main/cpp/util:filesystem", "//src/main/cpp/util:logging", "@com_google_googletest//:gtest_main", ], diff --git a/src/test/cpp/util/file_posix_test.cc b/src/test/cpp/util/file_posix_test.cc index 688042c8ed..75026af6b3 100644 --- a/src/test/cpp/util/file_posix_test.cc +++ b/src/test/cpp/util/file_posix_test.cc @@ -19,6 +19,8 @@ #include "src/main/cpp/util/file.h" #include "src/main/cpp/util/file_platform.h" +#include "src/main/cpp/util/path.h" +#include "src/main/cpp/util/path_platform.h" #include "src/test/cpp/util/test_util.h" #include "googletest/include/gtest/gtest.h" @@ -46,73 +48,6 @@ static bool CreateEmptyFile(const string& path) { return close(fd) == 0; } -TEST(FilePosixTest, TestDirname) { - // The Posix version of SplitPath (thus Dirname too, which is implemented on - // top of it) is not aware of Windows paths. - ASSERT_EQ("", Dirname("")); - ASSERT_EQ("/", Dirname("/")); - ASSERT_EQ("", Dirname("foo")); - ASSERT_EQ("/", Dirname("/foo")); - ASSERT_EQ("/foo", Dirname("/foo/")); - ASSERT_EQ("foo", Dirname("foo/bar")); - ASSERT_EQ("foo/bar", Dirname("foo/bar/baz")); - ASSERT_EQ("", Dirname("\\foo")); - ASSERT_EQ("", Dirname("\\foo\\")); - ASSERT_EQ("", Dirname("foo\\bar")); - ASSERT_EQ("", Dirname("foo\\bar\\baz")); - ASSERT_EQ("foo\\bar", Dirname("foo\\bar/baz\\qux")); - ASSERT_EQ("c:", Dirname("c:/")); - ASSERT_EQ("", Dirname("c:\\")); - ASSERT_EQ("c:", Dirname("c:/foo")); - ASSERT_EQ("", Dirname("c:\\foo")); - ASSERT_EQ("", Dirname("\\\\?\\c:\\")); - ASSERT_EQ("", Dirname("\\\\?\\c:\\foo")); -} - -TEST(FilePosixTest, TestBasename) { - // The Posix version of SplitPath (thus Basename too, which is implemented on - // top of it) is not aware of Windows paths. - ASSERT_EQ("", Basename("")); - ASSERT_EQ("", Basename("/")); - ASSERT_EQ("foo", Basename("foo")); - ASSERT_EQ("foo", Basename("/foo")); - ASSERT_EQ("", Basename("/foo/")); - ASSERT_EQ("bar", Basename("foo/bar")); - ASSERT_EQ("baz", Basename("foo/bar/baz")); - ASSERT_EQ("\\foo", Basename("\\foo")); - ASSERT_EQ("\\foo\\", Basename("\\foo\\")); - ASSERT_EQ("foo\\bar", Basename("foo\\bar")); - ASSERT_EQ("foo\\bar\\baz", Basename("foo\\bar\\baz")); - ASSERT_EQ("baz\\qux", Basename("foo\\bar/baz\\qux")); - ASSERT_EQ("qux", Basename("qux")); - ASSERT_EQ("", Basename("c:/")); - ASSERT_EQ("c:\\", Basename("c:\\")); - ASSERT_EQ("foo", Basename("c:/foo")); - ASSERT_EQ("c:\\foo", Basename("c:\\foo")); - ASSERT_EQ("\\\\?\\c:\\", Basename("\\\\?\\c:\\")); - ASSERT_EQ("\\\\?\\c:\\foo", Basename("\\\\?\\c:\\foo")); -} - -TEST(FilePosixTest, JoinPath) { - std::string path = JoinPath("", ""); - ASSERT_EQ("", path); - - path = JoinPath("a", "b"); - ASSERT_EQ("a/b", path); - - path = JoinPath("a/", "b"); - ASSERT_EQ("a/b", path); - - path = JoinPath("a", "/b"); - ASSERT_EQ("a/b", path); - - path = JoinPath("a/", "/b"); - ASSERT_EQ("a/b", path); - - path = JoinPath("/", "/"); - ASSERT_EQ("/", path); -} - void MockDirectoryListingFunction(const string& path, DirectoryEntryConsumer* consume) { if (path == "root") { @@ -272,24 +207,6 @@ TEST(FilePosixTest, CanAccess) { ASSERT_EQ(0, rmdir(dir.c_str())); } -TEST(FilePosixTest, GetCwd) { - char cwdbuf[PATH_MAX]; - ASSERT_EQ(cwdbuf, getcwd(cwdbuf, PATH_MAX)); - - // Assert that GetCwd() and getcwd() return the same value. - string cwd(cwdbuf); - ASSERT_EQ(cwd, blaze_util::GetCwd()); - - // Change to a different directory. - ASSERT_EQ(0, chdir("/usr")); - - // Assert that GetCwd() returns the new CWD. - ASSERT_EQ(string("/usr"), blaze_util::GetCwd()); - - ASSERT_EQ(0, chdir(cwd.c_str())); - ASSERT_EQ(cwd, blaze_util::GetCwd()); -} - TEST(FilePosixTest, ChangeDirectory) { // Retrieve the current working directory. char old_wd[PATH_MAX]; @@ -405,32 +322,4 @@ TEST(FilePosixTest, ForEachDirectoryEntry) { rmdir(root.c_str()); } -TEST(FilePosixTest, IsAbsolute) { - ASSERT_FALSE(IsAbsolute("")); - ASSERT_TRUE(IsAbsolute("/")); - ASSERT_TRUE(IsAbsolute("/foo")); - ASSERT_FALSE(IsAbsolute("\\")); - ASSERT_FALSE(IsAbsolute("\\foo")); - ASSERT_FALSE(IsAbsolute("c:")); - ASSERT_FALSE(IsAbsolute("c:/")); - ASSERT_FALSE(IsAbsolute("c:\\")); - ASSERT_FALSE(IsAbsolute("c:\\foo")); - ASSERT_FALSE(IsAbsolute("\\\\?\\c:\\")); - ASSERT_FALSE(IsAbsolute("\\\\?\\c:\\foo")); -} - -TEST(FilePosixTest, IsRootDirectory) { - ASSERT_FALSE(IsRootDirectory("")); - ASSERT_TRUE(IsRootDirectory("/")); - ASSERT_FALSE(IsRootDirectory("/foo")); - ASSERT_FALSE(IsRootDirectory("\\")); - ASSERT_FALSE(IsRootDirectory("\\foo")); - ASSERT_FALSE(IsRootDirectory("c:")); - ASSERT_FALSE(IsRootDirectory("c:/")); - ASSERT_FALSE(IsRootDirectory("c:\\")); - ASSERT_FALSE(IsRootDirectory("c:\\foo")); - ASSERT_FALSE(IsRootDirectory("\\\\?\\c:\\")); - ASSERT_FALSE(IsRootDirectory("\\\\?\\c:\\foo")); -} - } // namespace blaze_util diff --git a/src/test/cpp/util/file_test.cc b/src/test/cpp/util/file_test.cc index c05b3b9c24..5f6f6eaf11 100644 --- a/src/test/cpp/util/file_test.cc +++ b/src/test/cpp/util/file_test.cc @@ -21,6 +21,8 @@ #include <vector> #include "src/main/cpp/util/file.h" +#include "src/main/cpp/util/path.h" +#include "src/main/cpp/util/path_platform.h" #include "src/test/cpp/util/test_util.h" #include "googletest/include/gtest/gtest.h" diff --git a/src/test/cpp/util/file_windows_test.cc b/src/test/cpp/util/file_windows_test.cc index 87987b4d89..1844736d1e 100644 --- a/src/test/cpp/util/file_windows_test.cc +++ b/src/test/cpp/util/file_windows_test.cc @@ -22,6 +22,8 @@ #include "gtest/gtest.h" #include "src/main/cpp/util/file.h" #include "src/main/cpp/util/file_platform.h" +#include "src/main/cpp/util/path.h" +#include "src/main/cpp/util/path_platform.h" #include "src/main/cpp/util/strings.h" #include "src/main/native/windows/file.h" #include "src/main/native/windows/util.h" @@ -40,7 +42,6 @@ using std::unique_ptr; using std::wstring; // Methods defined in file_windows.cc that are only visible for testing. -bool AsWindowsPath(const string& path, wstring* result, string* error); string NormalizeWindowsPath(string path); class FileWindowsTest : public ::testing::Test { @@ -90,223 +91,6 @@ TEST_F(FileWindowsTest, TestTearDownB) { AssertTearDown(L"test.teardown.b", L"test.teardown.a"); } -TEST_F(FileWindowsTest, TestNormalizeWindowsPath) { - ASSERT_EQ(string(""), NormalizeWindowsPath("")); - ASSERT_EQ(string(""), NormalizeWindowsPath(".")); - ASSERT_EQ(string("foo"), NormalizeWindowsPath("foo")); - ASSERT_EQ(string("foo"), NormalizeWindowsPath("foo/")); - ASSERT_EQ(string("foo\\bar"), NormalizeWindowsPath("foo//bar")); - ASSERT_EQ(string("foo\\bar"), NormalizeWindowsPath("../..//foo/./bar")); - ASSERT_EQ(string("foo\\bar"), NormalizeWindowsPath("../foo/baz/../bar")); - ASSERT_EQ(string("c:\\"), NormalizeWindowsPath("c:")); - ASSERT_EQ(string("c:\\"), NormalizeWindowsPath("c:/")); - ASSERT_EQ(string("c:\\"), NormalizeWindowsPath("c:\\")); - ASSERT_EQ(string("c:\\foo\\bar"), NormalizeWindowsPath("c:\\..//foo/./bar/")); -} - -TEST_F(FileWindowsTest, TestDirname) { - ASSERT_EQ("", Dirname("")); - ASSERT_EQ("/", Dirname("/")); - ASSERT_EQ("", Dirname("foo")); - ASSERT_EQ("/", Dirname("/foo")); - ASSERT_EQ("/foo", Dirname("/foo/")); - ASSERT_EQ("foo", Dirname("foo/bar")); - ASSERT_EQ("foo/bar", Dirname("foo/bar/baz")); - ASSERT_EQ("\\", Dirname("\\foo")); - ASSERT_EQ("\\foo", Dirname("\\foo\\")); - ASSERT_EQ("foo", Dirname("foo\\bar")); - ASSERT_EQ("foo\\bar", Dirname("foo\\bar\\baz")); - ASSERT_EQ("foo\\bar/baz", Dirname("foo\\bar/baz\\qux")); - ASSERT_EQ("c:/", Dirname("c:/")); - ASSERT_EQ("c:\\", Dirname("c:\\")); - ASSERT_EQ("c:/", Dirname("c:/foo")); - ASSERT_EQ("c:\\", Dirname("c:\\foo")); - ASSERT_EQ("\\\\?\\c:\\", Dirname("\\\\?\\c:\\")); - ASSERT_EQ("\\\\?\\c:\\", Dirname("\\\\?\\c:\\foo")); -} - -TEST_F(FileWindowsTest, TestBasename) { - ASSERT_EQ("", Basename("")); - ASSERT_EQ("", Basename("/")); - ASSERT_EQ("foo", Basename("foo")); - ASSERT_EQ("foo", Basename("/foo")); - ASSERT_EQ("", Basename("/foo/")); - ASSERT_EQ("bar", Basename("foo/bar")); - ASSERT_EQ("baz", Basename("foo/bar/baz")); - ASSERT_EQ("foo", Basename("\\foo")); - ASSERT_EQ("", Basename("\\foo\\")); - ASSERT_EQ("bar", Basename("foo\\bar")); - ASSERT_EQ("baz", Basename("foo\\bar\\baz")); - ASSERT_EQ("qux", Basename("foo\\bar/baz\\qux")); - ASSERT_EQ("", Basename("c:/")); - ASSERT_EQ("", Basename("c:\\")); - ASSERT_EQ("foo", Basename("c:/foo")); - ASSERT_EQ("foo", Basename("c:\\foo")); - ASSERT_EQ("", Basename("\\\\?\\c:\\")); - ASSERT_EQ("foo", Basename("\\\\?\\c:\\foo")); -} - -TEST_F(FileWindowsTest, TestIsAbsolute) { - ASSERT_FALSE(IsAbsolute("")); - ASSERT_TRUE(IsAbsolute("/")); - ASSERT_TRUE(IsAbsolute("/foo")); - ASSERT_TRUE(IsAbsolute("\\")); - ASSERT_TRUE(IsAbsolute("\\foo")); - ASSERT_FALSE(IsAbsolute("c:")); - ASSERT_TRUE(IsAbsolute("c:/")); - ASSERT_TRUE(IsAbsolute("c:\\")); - ASSERT_TRUE(IsAbsolute("c:\\foo")); - ASSERT_TRUE(IsAbsolute("\\\\?\\c:\\")); - ASSERT_TRUE(IsAbsolute("\\\\?\\c:\\foo")); -} - -TEST_F(FileWindowsTest, TestIsRootDirectory) { - ASSERT_FALSE(IsRootDirectory("")); - ASSERT_TRUE(IsRootDirectory("/")); - ASSERT_FALSE(IsRootDirectory("/foo")); - ASSERT_TRUE(IsRootDirectory("\\")); - ASSERT_FALSE(IsRootDirectory("\\foo")); - ASSERT_FALSE(IsRootDirectory("c:")); - ASSERT_TRUE(IsRootDirectory("c:/")); - ASSERT_TRUE(IsRootDirectory("c:\\")); - ASSERT_FALSE(IsRootDirectory("c:\\foo")); - ASSERT_TRUE(IsRootDirectory("\\\\?\\c:\\")); - ASSERT_FALSE(IsRootDirectory("\\\\?\\c:\\foo")); -} - -TEST_F(FileWindowsTest, TestAsWindowsPath) { - SetEnvironmentVariableA("BAZEL_SH", "c:\\some\\long/path\\bin\\bash.exe"); - wstring actual; - - // Null and empty input produces empty result. - ASSERT_TRUE(AsWindowsPath("", &actual, nullptr)); - ASSERT_EQ(wstring(L""), actual); - - // If the path has a "\\?\" prefix, AsWindowsPath assumes it's a correct - // Windows path. If it's not, the Windows API function that we pass the path - // to will fail anyway. - ASSERT_TRUE(AsWindowsPath("\\\\?\\anything/..", &actual, nullptr)); - ASSERT_EQ(wstring(L"\\\\?\\anything/.."), actual); - - // Trailing slash or backslash is removed. - ASSERT_TRUE(AsWindowsPath("foo/", &actual, nullptr)); - ASSERT_EQ(wstring(L"foo"), actual); - ASSERT_TRUE(AsWindowsPath("foo\\", &actual, nullptr)); - ASSERT_EQ(wstring(L"foo"), actual); - - // Slashes are converted to backslash. - ASSERT_TRUE(AsWindowsPath("foo/bar", &actual, nullptr)); - ASSERT_EQ(wstring(L"foo\\bar"), actual); - ASSERT_TRUE(AsWindowsPath("c:/", &actual, nullptr)); - ASSERT_EQ(wstring(L"c:\\"), actual); - ASSERT_TRUE(AsWindowsPath("c:\\", &actual, nullptr)); - ASSERT_EQ(wstring(L"c:\\"), actual); - - // Invalid paths - string error; - ASSERT_FALSE(AsWindowsPath("c:", &actual, &error)); - EXPECT_TRUE(error.find("working-directory relative paths") != string::npos); - ASSERT_FALSE(AsWindowsPath("c:foo", &actual, &error)); - EXPECT_TRUE(error.find("working-directory relative paths") != string::npos); - ASSERT_FALSE(AsWindowsPath("\\\\foo", &actual, &error)); - EXPECT_TRUE(error.find("network paths") != string::npos); - - // /dev/null and NUL produce NUL. - ASSERT_TRUE(AsWindowsPath("/dev/null", &actual, nullptr)); - ASSERT_EQ(wstring(L"NUL"), actual); - ASSERT_TRUE(AsWindowsPath("Nul", &actual, nullptr)); - ASSERT_EQ(wstring(L"NUL"), actual); - - // MSYS path with drive letter. - ASSERT_FALSE(AsWindowsPath("/c", &actual, &error)); - EXPECT_TRUE(error.find("Unix-style") != string::npos); - ASSERT_FALSE(AsWindowsPath("/c/", &actual, &error)); - EXPECT_TRUE(error.find("Unix-style") != string::npos); - - // Absolute-on-current-drive path gets a drive letter. - ASSERT_TRUE(AsWindowsPath("\\foo", &actual, nullptr)); - ASSERT_EQ(wstring(1, GetCwd()[0]) + L":\\foo", actual); - - // Even for long paths, AsWindowsPath doesn't add a "\\?\" prefix (it's the - // caller's duty to do so). - wstring wlongpath(L"dummy_long_path\\"); - string longpath("dummy_long_path/"); - while (longpath.size() <= MAX_PATH) { - wlongpath += wlongpath; - longpath += longpath; - } - wlongpath.pop_back(); // remove trailing "\" - ASSERT_TRUE(AsWindowsPath(longpath, &actual, nullptr)); - ASSERT_EQ(wlongpath, actual); -} - -TEST_F(FileWindowsTest, TestAsAbsoluteWindowsPath) { - SetEnvironmentVariableA("BAZEL_SH", "c:\\some\\long/path\\bin\\bash.exe"); - wstring actual; - - ASSERT_TRUE(AsAbsoluteWindowsPath("c:/", &actual, nullptr)); - ASSERT_EQ(L"\\\\?\\c:\\", actual); - - ASSERT_TRUE(AsAbsoluteWindowsPath("c:/..\\non-existent//", &actual, nullptr)); - ASSERT_EQ(L"\\\\?\\c:\\non-existent", actual); - - WCHAR cwd[MAX_PATH]; - wstring cwdw(CstringToWstring(GetCwd().c_str()).get()); - wstring expected = - wstring(L"\\\\?\\") + cwdw + - ((cwdw.back() == L'\\') ? L"non-existent" : L"\\non-existent"); - ASSERT_TRUE(AsAbsoluteWindowsPath("non-existent", &actual, nullptr)); - ASSERT_EQ(actual, expected); -} - -TEST_F(FileWindowsTest, TestAsShortWindowsPath) { - string actual; - ASSERT_TRUE(AsShortWindowsPath("/dev/null", &actual, nullptr)); - ASSERT_EQ(string("NUL"), actual); - - ASSERT_TRUE(AsShortWindowsPath("nul", &actual, nullptr)); - ASSERT_EQ(string("NUL"), actual); - - ASSERT_TRUE(AsShortWindowsPath("C://", &actual, nullptr)); - ASSERT_EQ(string("c:\\"), actual); - - string error; - ASSERT_FALSE(AsShortWindowsPath("/C//", &actual, &error)); - EXPECT_TRUE(error.find("Unix-style") != string::npos); - - // The A drive usually doesn't exist but AsShortWindowsPath should still work. - // Here we even have multiple trailing slashes, that should be handled too. - ASSERT_TRUE(AsShortWindowsPath("A://", &actual, nullptr)); - ASSERT_EQ(string("a:\\"), actual); - - // Assert that we can shorten the TEST_TMPDIR. - string tmpdir; - GET_TEST_TMPDIR(tmpdir); - string short_tmpdir; - ASSERT_TRUE(AsShortWindowsPath(tmpdir, &short_tmpdir, nullptr)); - ASSERT_LT(0, short_tmpdir.size()); - ASSERT_TRUE(PathExists(short_tmpdir)); - - // Assert that a trailing "/" doesn't change the shortening logic and it will - // be stripped from the result. - ASSERT_TRUE(AsShortWindowsPath(tmpdir + "/", &actual, nullptr)); - ASSERT_EQ(actual, short_tmpdir); - ASSERT_NE(actual.back(), '/'); - ASSERT_NE(actual.back(), '\\'); - - // Assert shortening another long path, and that the result is lowercased. - string dirname(JoinPath(short_tmpdir, "LONGpathNAME")); - ASSERT_EQ(0, mkdir(dirname.c_str())); - ASSERT_TRUE(PathExists(dirname)); - ASSERT_TRUE(AsShortWindowsPath(dirname, &actual, nullptr)); - ASSERT_EQ(short_tmpdir + "\\longpa~1", actual); - - // Assert shortening non-existent paths. - ASSERT_TRUE(AsShortWindowsPath(JoinPath(tmpdir, "NonExistent/FOO"), &actual, - nullptr)); - ASSERT_EQ(short_tmpdir + "\\nonexistent\\foo", actual); -} - TEST_F(FileWindowsTest, TestMsysRootRetrieval) { wstring actual; @@ -513,18 +297,4 @@ TEST_F(FileWindowsTest, TestMakeCanonical) { ASSERT_EQ(dircanon, symcanon); } -TEST(FileTest, IsWindowsDevNullTest) { - ASSERT_TRUE(IsDevNull("nul")); - ASSERT_TRUE(IsDevNull("NUL")); - ASSERT_TRUE(IsDevNull("nuL")); - ASSERT_TRUE(IsDevNull("/dev/null")); - ASSERT_FALSE(IsDevNull("/Dev/Null")); - ASSERT_FALSE(IsDevNull("dev/null")); - ASSERT_FALSE(IsDevNull("/dev/nul")); - ASSERT_FALSE(IsDevNull("/dev/nulll")); - ASSERT_FALSE(IsDevNull("nu")); - ASSERT_FALSE(IsDevNull(NULL)); - ASSERT_FALSE(IsDevNull("")); -} - } // namespace blaze_util diff --git a/src/test/cpp/util/logging_test.cc b/src/test/cpp/util/logging_test.cc index f3ced048a2..d48c177e75 100644 --- a/src/test/cpp/util/logging_test.cc +++ b/src/test/cpp/util/logging_test.cc @@ -20,6 +20,7 @@ #include "src/main/cpp/util/bazel_log_handler.h" #include "src/main/cpp/util/file.h" #include "src/main/cpp/util/logging.h" +#include "src/main/cpp/util/path.h" #include "googlemock/include/gmock/gmock.h" #include "googletest/include/gtest/gtest.h" diff --git a/src/test/cpp/util/path_posix_test.cc b/src/test/cpp/util/path_posix_test.cc new file mode 100644 index 0000000000..7d0e4979bf --- /dev/null +++ b/src/test/cpp/util/path_posix_test.cc @@ -0,0 +1,162 @@ +// Copyright 2018 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#include <fcntl.h> +#include <limits.h> +#include <unistd.h> + +#include <algorithm> + +#include "src/main/cpp/util/file_platform.h" +#include "src/main/cpp/util/path.h" +#include "src/main/cpp/util/path_platform.h" +#include "src/test/cpp/util/test_util.h" +#include "googletest/include/gtest/gtest.h" + +namespace blaze_util { + +using std::pair; +using std::string; +using std::vector; + +TEST(PathPosixTest, TestDirname) { + // The Posix version of SplitPath (thus Dirname too, which is implemented on + // top of it) is not aware of Windows paths. + ASSERT_EQ("", Dirname("")); + ASSERT_EQ("/", Dirname("/")); + ASSERT_EQ("", Dirname("foo")); + ASSERT_EQ("/", Dirname("/foo")); + ASSERT_EQ("/foo", Dirname("/foo/")); + ASSERT_EQ("foo", Dirname("foo/bar")); + ASSERT_EQ("foo/bar", Dirname("foo/bar/baz")); + ASSERT_EQ("", Dirname("\\foo")); + ASSERT_EQ("", Dirname("\\foo\\")); + ASSERT_EQ("", Dirname("foo\\bar")); + ASSERT_EQ("", Dirname("foo\\bar\\baz")); + ASSERT_EQ("foo\\bar", Dirname("foo\\bar/baz\\qux")); + ASSERT_EQ("c:", Dirname("c:/")); + ASSERT_EQ("", Dirname("c:\\")); + ASSERT_EQ("c:", Dirname("c:/foo")); + ASSERT_EQ("", Dirname("c:\\foo")); + ASSERT_EQ("", Dirname("\\\\?\\c:\\")); + ASSERT_EQ("", Dirname("\\\\?\\c:\\foo")); +} + +TEST(PathPosixTest, TestBasename) { + // The Posix version of SplitPath (thus Basename too, which is implemented on + // top of it) is not aware of Windows paths. + ASSERT_EQ("", Basename("")); + ASSERT_EQ("", Basename("/")); + ASSERT_EQ("foo", Basename("foo")); + ASSERT_EQ("foo", Basename("/foo")); + ASSERT_EQ("", Basename("/foo/")); + ASSERT_EQ("bar", Basename("foo/bar")); + ASSERT_EQ("baz", Basename("foo/bar/baz")); + ASSERT_EQ("\\foo", Basename("\\foo")); + ASSERT_EQ("\\foo\\", Basename("\\foo\\")); + ASSERT_EQ("foo\\bar", Basename("foo\\bar")); + ASSERT_EQ("foo\\bar\\baz", Basename("foo\\bar\\baz")); + ASSERT_EQ("baz\\qux", Basename("foo\\bar/baz\\qux")); + ASSERT_EQ("qux", Basename("qux")); + ASSERT_EQ("", Basename("c:/")); + ASSERT_EQ("c:\\", Basename("c:\\")); + ASSERT_EQ("foo", Basename("c:/foo")); + ASSERT_EQ("c:\\foo", Basename("c:\\foo")); + ASSERT_EQ("\\\\?\\c:\\", Basename("\\\\?\\c:\\")); + ASSERT_EQ("\\\\?\\c:\\foo", Basename("\\\\?\\c:\\foo")); +} + +TEST(PathPosixTest, JoinPath) { + std::string path = JoinPath("", ""); + ASSERT_EQ("", path); + + path = JoinPath("a", "b"); + ASSERT_EQ("a/b", path); + + path = JoinPath("a/", "b"); + ASSERT_EQ("a/b", path); + + path = JoinPath("a", "/b"); + ASSERT_EQ("a/b", path); + + path = JoinPath("a/", "/b"); + ASSERT_EQ("a/b", path); + + path = JoinPath("/", "/"); + ASSERT_EQ("/", path); +} + +TEST(PathPosixTest, GetCwd) { + char cwdbuf[PATH_MAX]; + ASSERT_EQ(cwdbuf, getcwd(cwdbuf, PATH_MAX)); + + // Assert that GetCwd() and getcwd() return the same value. + string cwd(cwdbuf); + ASSERT_EQ(cwd, blaze_util::GetCwd()); + + // Change to a different directory. + ASSERT_EQ(0, chdir("/usr")); + + // Assert that GetCwd() returns the new CWD. + ASSERT_EQ(string("/usr"), blaze_util::GetCwd()); + + ASSERT_EQ(0, chdir(cwd.c_str())); + ASSERT_EQ(cwd, blaze_util::GetCwd()); +} + +TEST(PathPosixTest, IsAbsolute) { + ASSERT_FALSE(IsAbsolute("")); + ASSERT_TRUE(IsAbsolute("/")); + ASSERT_TRUE(IsAbsolute("/foo")); + ASSERT_FALSE(IsAbsolute("\\")); + ASSERT_FALSE(IsAbsolute("\\foo")); + ASSERT_FALSE(IsAbsolute("c:")); + ASSERT_FALSE(IsAbsolute("c:/")); + ASSERT_FALSE(IsAbsolute("c:\\")); + ASSERT_FALSE(IsAbsolute("c:\\foo")); + ASSERT_FALSE(IsAbsolute("\\\\?\\c:\\")); + ASSERT_FALSE(IsAbsolute("\\\\?\\c:\\foo")); +} + +TEST(PathPosixTest, IsRootDirectory) { + ASSERT_FALSE(IsRootDirectory("")); + ASSERT_TRUE(IsRootDirectory("/")); + ASSERT_FALSE(IsRootDirectory("/foo")); + ASSERT_FALSE(IsRootDirectory("\\")); + ASSERT_FALSE(IsRootDirectory("\\foo")); + ASSERT_FALSE(IsRootDirectory("c:")); + ASSERT_FALSE(IsRootDirectory("c:/")); + ASSERT_FALSE(IsRootDirectory("c:\\")); + ASSERT_FALSE(IsRootDirectory("c:\\foo")); + ASSERT_FALSE(IsRootDirectory("\\\\?\\c:\\")); + ASSERT_FALSE(IsRootDirectory("\\\\?\\c:\\foo")); +} + +TEST(PathPosixTest, IsDevNullTest) { + ASSERT_TRUE(IsDevNull("/dev/null")); + ASSERT_FALSE(IsDevNull("dev/null")); + ASSERT_FALSE(IsDevNull("/dev/nul")); + ASSERT_FALSE(IsDevNull("/dev/nulll")); + ASSERT_FALSE(IsDevNull(NULL)); + ASSERT_FALSE(IsDevNull("")); +} + +TEST(PathPosixTest, MakeAbsolute) { + EXPECT_EQ(MakeAbsolute("/foo/bar"), "/foo/bar"); + EXPECT_EQ(MakeAbsolute("/foo/bar/"), "/foo/bar/"); + EXPECT_EQ(MakeAbsolute("foo"), blaze_util::GetCwd() + "/foo"); + EXPECT_EQ(MakeAbsolute(std::string()), blaze_util::GetCwd()); + EXPECT_EQ(MakeAbsolute("/dev/null"), "/dev/null"); +} + +} // namespace blaze_util diff --git a/src/test/cpp/util/path_windows_test.cc b/src/test/cpp/util/path_windows_test.cc new file mode 100644 index 0000000000..789f67cdaa --- /dev/null +++ b/src/test/cpp/util/path_windows_test.cc @@ -0,0 +1,318 @@ +// Copyright 2016 The Bazel Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#include <stdio.h> +#include <string.h> +#include <windows.h> + +#include <algorithm> +#include <memory> +#include <string> + +#include "gtest/gtest.h" +#include "src/main/cpp/util/file_platform.h" +#include "src/main/cpp/util/path.h" +#include "src/main/cpp/util/path_platform.h" +#include "src/main/cpp/util/strings.h" +#include "src/main/native/windows/file.h" +#include "src/main/native/windows/util.h" +#include "src/test/cpp/util/test_util.h" +#include "src/test/cpp/util/windows_test_util.h" + +#if !defined(COMPILER_MSVC) && !defined(__CYGWIN__) +#error("This test should only be run on Windows") +#endif // !defined(COMPILER_MSVC) && !defined(__CYGWIN__) + +namespace blaze_util { + +using bazel::windows::CreateJunction; +using std::string; +using std::unique_ptr; +using std::wstring; + +// Methods defined in path_windows.cc that are only visible for testing. +string NormalizeWindowsPath(string path); + +TEST(PathWindowsTest, TestNormalizeWindowsPath) { + ASSERT_EQ(string(""), NormalizeWindowsPath("")); + ASSERT_EQ(string(""), NormalizeWindowsPath(".")); + ASSERT_EQ(string("foo"), NormalizeWindowsPath("foo")); + ASSERT_EQ(string("foo"), NormalizeWindowsPath("foo/")); + ASSERT_EQ(string("foo\\bar"), NormalizeWindowsPath("foo//bar")); + ASSERT_EQ(string("foo\\bar"), NormalizeWindowsPath("../..//foo/./bar")); + ASSERT_EQ(string("foo\\bar"), NormalizeWindowsPath("../foo/baz/../bar")); + ASSERT_EQ(string("c:\\"), NormalizeWindowsPath("c:")); + ASSERT_EQ(string("c:\\"), NormalizeWindowsPath("c:/")); + ASSERT_EQ(string("c:\\"), NormalizeWindowsPath("c:\\")); + ASSERT_EQ(string("c:\\foo\\bar"), NormalizeWindowsPath("c:\\..//foo/./bar/")); +} + +TEST(PathWindowsTest, TestDirname) { + ASSERT_EQ("", Dirname("")); + ASSERT_EQ("/", Dirname("/")); + ASSERT_EQ("", Dirname("foo")); + ASSERT_EQ("/", Dirname("/foo")); + ASSERT_EQ("/foo", Dirname("/foo/")); + ASSERT_EQ("foo", Dirname("foo/bar")); + ASSERT_EQ("foo/bar", Dirname("foo/bar/baz")); + ASSERT_EQ("\\", Dirname("\\foo")); + ASSERT_EQ("\\foo", Dirname("\\foo\\")); + ASSERT_EQ("foo", Dirname("foo\\bar")); + ASSERT_EQ("foo\\bar", Dirname("foo\\bar\\baz")); + ASSERT_EQ("foo\\bar/baz", Dirname("foo\\bar/baz\\qux")); + ASSERT_EQ("c:/", Dirname("c:/")); + ASSERT_EQ("c:\\", Dirname("c:\\")); + ASSERT_EQ("c:/", Dirname("c:/foo")); + ASSERT_EQ("c:\\", Dirname("c:\\foo")); + ASSERT_EQ("\\\\?\\c:\\", Dirname("\\\\?\\c:\\")); + ASSERT_EQ("\\\\?\\c:\\", Dirname("\\\\?\\c:\\foo")); +} + +TEST(PathWindowsTest, TestBasename) { + ASSERT_EQ("", Basename("")); + ASSERT_EQ("", Basename("/")); + ASSERT_EQ("foo", Basename("foo")); + ASSERT_EQ("foo", Basename("/foo")); + ASSERT_EQ("", Basename("/foo/")); + ASSERT_EQ("bar", Basename("foo/bar")); + ASSERT_EQ("baz", Basename("foo/bar/baz")); + ASSERT_EQ("foo", Basename("\\foo")); + ASSERT_EQ("", Basename("\\foo\\")); + ASSERT_EQ("bar", Basename("foo\\bar")); + ASSERT_EQ("baz", Basename("foo\\bar\\baz")); + ASSERT_EQ("qux", Basename("foo\\bar/baz\\qux")); + ASSERT_EQ("", Basename("c:/")); + ASSERT_EQ("", Basename("c:\\")); + ASSERT_EQ("foo", Basename("c:/foo")); + ASSERT_EQ("foo", Basename("c:\\foo")); + ASSERT_EQ("", Basename("\\\\?\\c:\\")); + ASSERT_EQ("foo", Basename("\\\\?\\c:\\foo")); +} + +TEST(PathWindowsTest, TestIsAbsolute) { + ASSERT_FALSE(IsAbsolute("")); + ASSERT_TRUE(IsAbsolute("/")); + ASSERT_TRUE(IsAbsolute("/foo")); + ASSERT_TRUE(IsAbsolute("\\")); + ASSERT_TRUE(IsAbsolute("\\foo")); + ASSERT_FALSE(IsAbsolute("c:")); + ASSERT_TRUE(IsAbsolute("c:/")); + ASSERT_TRUE(IsAbsolute("c:\\")); + ASSERT_TRUE(IsAbsolute("c:\\foo")); + ASSERT_TRUE(IsAbsolute("\\\\?\\c:\\")); + ASSERT_TRUE(IsAbsolute("\\\\?\\c:\\foo")); +} + +TEST(PathWindowsTest, TestIsRootDirectory) { + ASSERT_FALSE(IsRootDirectory("")); + ASSERT_TRUE(IsRootDirectory("/")); + ASSERT_FALSE(IsRootDirectory("/foo")); + ASSERT_TRUE(IsRootDirectory("\\")); + ASSERT_FALSE(IsRootDirectory("\\foo")); + ASSERT_FALSE(IsRootDirectory("c:")); + ASSERT_TRUE(IsRootDirectory("c:/")); + ASSERT_TRUE(IsRootDirectory("c:\\")); + ASSERT_FALSE(IsRootDirectory("c:\\foo")); + ASSERT_TRUE(IsRootDirectory("\\\\?\\c:\\")); + ASSERT_FALSE(IsRootDirectory("\\\\?\\c:\\foo")); +} + +TEST(PathWindowsTest, TestAsWindowsPath) { + SetEnvironmentVariableA("BAZEL_SH", "c:\\some\\long/path\\bin\\bash.exe"); + wstring actual; + + // Null and empty input produces empty result. + ASSERT_TRUE(AsWindowsPath("", &actual, nullptr)); + ASSERT_EQ(wstring(L""), actual); + + // If the path has a "\\?\" prefix, AsWindowsPath assumes it's a correct + // Windows path. If it's not, the Windows API function that we pass the path + // to will fail anyway. + ASSERT_TRUE(AsWindowsPath("\\\\?\\anything/..", &actual, nullptr)); + ASSERT_EQ(wstring(L"\\\\?\\anything/.."), actual); + + // Trailing slash or backslash is removed. + ASSERT_TRUE(AsWindowsPath("foo/", &actual, nullptr)); + ASSERT_EQ(wstring(L"foo"), actual); + ASSERT_TRUE(AsWindowsPath("foo\\", &actual, nullptr)); + ASSERT_EQ(wstring(L"foo"), actual); + + // Slashes are converted to backslash. + ASSERT_TRUE(AsWindowsPath("foo/bar", &actual, nullptr)); + ASSERT_EQ(wstring(L"foo\\bar"), actual); + ASSERT_TRUE(AsWindowsPath("c:/", &actual, nullptr)); + ASSERT_EQ(wstring(L"c:\\"), actual); + ASSERT_TRUE(AsWindowsPath("c:\\", &actual, nullptr)); + ASSERT_EQ(wstring(L"c:\\"), actual); + + // Invalid paths + string error; + ASSERT_FALSE(AsWindowsPath("c:", &actual, &error)); + EXPECT_TRUE(error.find("working-directory relative paths") != string::npos); + ASSERT_FALSE(AsWindowsPath("c:foo", &actual, &error)); + EXPECT_TRUE(error.find("working-directory relative paths") != string::npos); + ASSERT_FALSE(AsWindowsPath("\\\\foo", &actual, &error)); + EXPECT_TRUE(error.find("network paths") != string::npos); + + // /dev/null and NUL produce NUL. + ASSERT_TRUE(AsWindowsPath("/dev/null", &actual, nullptr)); + ASSERT_EQ(wstring(L"NUL"), actual); + ASSERT_TRUE(AsWindowsPath("Nul", &actual, nullptr)); + ASSERT_EQ(wstring(L"NUL"), actual); + + // MSYS path with drive letter. + ASSERT_FALSE(AsWindowsPath("/c", &actual, &error)); + EXPECT_TRUE(error.find("Unix-style") != string::npos); + ASSERT_FALSE(AsWindowsPath("/c/", &actual, &error)); + EXPECT_TRUE(error.find("Unix-style") != string::npos); + + // Absolute-on-current-drive path gets a drive letter. + ASSERT_TRUE(AsWindowsPath("\\foo", &actual, nullptr)); + ASSERT_EQ(wstring(1, GetCwd()[0]) + L":\\foo", actual); + + // Even for long paths, AsWindowsPath doesn't add a "\\?\" prefix (it's the + // caller's duty to do so). + wstring wlongpath(L"dummy_long_path\\"); + string longpath("dummy_long_path/"); + while (longpath.size() <= MAX_PATH) { + wlongpath += wlongpath; + longpath += longpath; + } + wlongpath.pop_back(); // remove trailing "\" + ASSERT_TRUE(AsWindowsPath(longpath, &actual, nullptr)); + ASSERT_EQ(wlongpath, actual); +} + +TEST(PathWindowsTest, TestAsAbsoluteWindowsPath) { + SetEnvironmentVariableA("BAZEL_SH", "c:\\some\\long/path\\bin\\bash.exe"); + wstring actual; + + ASSERT_TRUE(AsAbsoluteWindowsPath("c:/", &actual, nullptr)); + ASSERT_EQ(L"\\\\?\\c:\\", actual); + + ASSERT_TRUE(AsAbsoluteWindowsPath("c:/..\\non-existent//", &actual, nullptr)); + ASSERT_EQ(L"\\\\?\\c:\\non-existent", actual); + + WCHAR cwd[MAX_PATH]; + wstring cwdw(CstringToWstring(GetCwd().c_str()).get()); + wstring expected = + wstring(L"\\\\?\\") + cwdw + + ((cwdw.back() == L'\\') ? L"non-existent" : L"\\non-existent"); + ASSERT_TRUE(AsAbsoluteWindowsPath("non-existent", &actual, nullptr)); + ASSERT_EQ(actual, expected); +} + +TEST(PathWindowsTest, TestAsShortWindowsPath) { + string actual; + ASSERT_TRUE(AsShortWindowsPath("/dev/null", &actual, nullptr)); + ASSERT_EQ(string("NUL"), actual); + + ASSERT_TRUE(AsShortWindowsPath("nul", &actual, nullptr)); + ASSERT_EQ(string("NUL"), actual); + + ASSERT_TRUE(AsShortWindowsPath("C://", &actual, nullptr)); + ASSERT_EQ(string("c:\\"), actual); + + string error; + ASSERT_FALSE(AsShortWindowsPath("/C//", &actual, &error)); + EXPECT_TRUE(error.find("Unix-style") != string::npos); + + // The A drive usually doesn't exist but AsShortWindowsPath should still work. + // Here we even have multiple trailing slashes, that should be handled too. + ASSERT_TRUE(AsShortWindowsPath("A://", &actual, nullptr)); + ASSERT_EQ(string("a:\\"), actual); + + // Assert that we can shorten the TEST_TMPDIR. + char buf[MAX_PATH] = {0}; + DWORD len = ::GetEnvironmentVariableA("TEST_TMPDIR", buf, MAX_PATH); + string tmpdir = buf; + ASSERT_GT(tmpdir.size(), 0); + string short_tmpdir; + ASSERT_TRUE(AsShortWindowsPath(tmpdir, &short_tmpdir, nullptr)); + ASSERT_LT(0, short_tmpdir.size()); + ASSERT_TRUE(PathExists(short_tmpdir)); + + // Assert that a trailing "/" doesn't change the shortening logic and it will + // be stripped from the result. + ASSERT_TRUE(AsShortWindowsPath(tmpdir + "/", &actual, nullptr)); + ASSERT_EQ(actual, short_tmpdir); + ASSERT_NE(actual.back(), '/'); + ASSERT_NE(actual.back(), '\\'); + + // Assert shortening another long path, and that the result is lowercased. + string dirname(JoinPath(short_tmpdir, "LONGpathNAME")); + ASSERT_EQ(0, mkdir(dirname.c_str())); + ASSERT_TRUE(PathExists(dirname)); + ASSERT_TRUE(AsShortWindowsPath(dirname, &actual, nullptr)); + ASSERT_EQ(short_tmpdir + "\\longpa~1", actual); + + // Assert shortening non-existent paths. + ASSERT_TRUE(AsShortWindowsPath(JoinPath(tmpdir, "NonExistent/FOO"), &actual, + nullptr)); + ASSERT_EQ(short_tmpdir + "\\nonexistent\\foo", actual); +} + +TEST(PathWindowsTest, TestMsysRootRetrieval) { + wstring actual; + + // We just need "bin/<something>" or "usr/bin/<something>". + // Forward slashes are converted to backslashes. + SetEnvironmentVariableA("BAZEL_SH", "c:/foo\\bin/some_bash.exe"); + + string error; + ASSERT_FALSE(AsWindowsPath("/blah", &actual, &error)); + EXPECT_TRUE(error.find("Unix-style") != string::npos); + + SetEnvironmentVariableA("BAZEL_SH", "c:/tools/msys64/usr/bin/bash.exe"); + ASSERT_FALSE(AsWindowsPath("/blah", &actual, &error)); + EXPECT_TRUE(error.find("Unix-style") != string::npos); +} + +TEST(PathWindowsTest, IsWindowsDevNullTest) { + ASSERT_TRUE(IsDevNull("nul")); + ASSERT_TRUE(IsDevNull("NUL")); + ASSERT_TRUE(IsDevNull("nuL")); + ASSERT_TRUE(IsDevNull("/dev/null")); + ASSERT_FALSE(IsDevNull("/Dev/Null")); + ASSERT_FALSE(IsDevNull("dev/null")); + ASSERT_FALSE(IsDevNull("/dev/nul")); + ASSERT_FALSE(IsDevNull("/dev/nulll")); + ASSERT_FALSE(IsDevNull("nu")); + ASSERT_FALSE(IsDevNull(NULL)); + ASSERT_FALSE(IsDevNull("")); +} + +TEST(PathWindowsTest, ConvertPathTest) { + EXPECT_EQ("c:\\foo", ConvertPath("C:\\FOO")); + EXPECT_EQ("c:\\", ConvertPath("c:/")); + EXPECT_EQ("c:\\foo\\bar", ConvertPath("c:/../foo\\BAR\\.\\")); + EXPECT_EQ("nul", MakeAbsolute("NUL")); + EXPECT_EQ("nul", MakeAbsolute("nul")); + EXPECT_EQ("nul", MakeAbsolute("/dev/null")); +} + +TEST(PathWindowsTest, TestMakeAbsolute) { + EXPECT_EQ("c:\\foo\\bar", MakeAbsolute("C:\\foo\\BAR")); + EXPECT_EQ("c:\\foo\\bar", MakeAbsolute("C:/foo/bar")); + EXPECT_EQ("c:\\foo\\bar", MakeAbsolute("C:\\foo\\bar\\")); + EXPECT_EQ("c:\\foo\\bar", MakeAbsolute("C:/foo/bar/")); + EXPECT_EQ(blaze_util::AsLower(blaze_util::GetCwd()) + "\\foo", + MakeAbsolute("foo")); + EXPECT_EQ("nul", MakeAbsolute("NUL")); + EXPECT_EQ("nul", MakeAbsolute("Nul")); + EXPECT_EQ("nul", MakeAbsolute("nul")); + EXPECT_EQ(blaze_util::AsLower(blaze_util::GetCwd()), MakeAbsolute("")); + EXPECT_EQ("nul", MakeAbsolute("/dev/null")); +} + +} // namespace blaze_util diff --git a/src/test/cpp/workspace_layout_test.cc b/src/test/cpp/workspace_layout_test.cc index 8ac4fcb94a..4e17d6464b 100644 --- a/src/test/cpp/workspace_layout_test.cc +++ b/src/test/cpp/workspace_layout_test.cc @@ -20,6 +20,7 @@ #include "src/main/cpp/blaze_util_platform.h" #include "src/main/cpp/util/file.h" +#include "src/main/cpp/util/path.h" #include "googletest/include/gtest/gtest.h" namespace blaze { diff --git a/src/test/shell/bazel/testdata/embedded_tools_srcs_deps b/src/test/shell/bazel/testdata/embedded_tools_srcs_deps index 47f15a1d2f..10a614141b 100644 --- a/src/test/shell/bazel/testdata/embedded_tools_srcs_deps +++ b/src/test/shell/bazel/testdata/embedded_tools_srcs_deps @@ -30,7 +30,7 @@ //src/main/cpp/util:util //src/main/cpp/util:numbers //src/main/cpp/util:md5 -//src/main/cpp/util:file +//src/main/cpp/util:filesystem //src/main/native/windows:lib-file //src/main/native/windows:lib-util //src/main/cpp/util:strings diff --git a/src/tools/launcher/BUILD b/src/tools/launcher/BUILD index 37b0e4dddc..075ee57d1f 100644 --- a/src/tools/launcher/BUILD +++ b/src/tools/launcher/BUILD @@ -28,7 +28,7 @@ cc_library( srcs = ["launcher.cc"], hdrs = ["launcher.h"], deps = [ - "//src/main/cpp/util:file", + "//src/main/cpp/util:filesystem", "//src/tools/launcher/util", "//src/tools/launcher/util:data_parser", ], diff --git a/src/tools/launcher/java_launcher.cc b/src/tools/launcher/java_launcher.cc index 5b5a498b71..8daf209d17 100644 --- a/src/tools/launcher/java_launcher.cc +++ b/src/tools/launcher/java_launcher.cc @@ -20,6 +20,7 @@ #include "src/main/cpp/util/file.h" #include "src/main/cpp/util/file_platform.h" +#include "src/main/cpp/util/path_platform.h" #include "src/main/cpp/util/strings.h" #include "src/main/native/windows/file.h" #include "src/tools/launcher/java_launcher.h" diff --git a/src/tools/launcher/launcher.cc b/src/tools/launcher/launcher.cc index ea58e2cb75..9bcc3642c2 100644 --- a/src/tools/launcher/launcher.cc +++ b/src/tools/launcher/launcher.cc @@ -20,7 +20,7 @@ #include <string> #include <vector> -#include "src/main/cpp/util/file_platform.h" +#include "src/main/cpp/util/path_platform.h" #include "src/tools/launcher/launcher.h" #include "src/tools/launcher/util/data_parser.h" #include "src/tools/launcher/util/launcher_util.h" diff --git a/src/tools/launcher/util/BUILD b/src/tools/launcher/util/BUILD index 8d128c3ee7..d8927c6f35 100644 --- a/src/tools/launcher/util/BUILD +++ b/src/tools/launcher/util/BUILD @@ -19,7 +19,7 @@ cc_library( name = "util", srcs = ["launcher_util.cc"], hdrs = ["launcher_util.h"], - deps = ["//src/main/cpp/util:file"], + deps = ["//src/main/cpp/util:filesystem"], ) cc_test( diff --git a/src/tools/launcher/util/launcher_util.cc b/src/tools/launcher/util/launcher_util.cc index 2ef25a352f..3509ce3287 100644 --- a/src/tools/launcher/util/launcher_util.cc +++ b/src/tools/launcher/util/launcher_util.cc @@ -23,7 +23,7 @@ #include <sstream> #include <string> -#include "src/main/cpp/util/file_platform.h" +#include "src/main/cpp/util/path_platform.h" #include "src/tools/launcher/util/launcher_util.h" namespace bazel { diff --git a/src/tools/singlejar/test_util.cc b/src/tools/singlejar/test_util.cc index f8ea0de8a3..722df5dc2a 100644 --- a/src/tools/singlejar/test_util.cc +++ b/src/tools/singlejar/test_util.cc @@ -22,6 +22,7 @@ #include "src/main/cpp/util/file.h" #include "src/main/cpp/util/file_platform.h" +#include "src/main/cpp/util/path.h" #include "src/main/cpp/util/strings.h" #include "googletest/include/gtest/gtest.h" diff --git a/third_party/ijar/BUILD b/third_party/ijar/BUILD index 96f4066c01..4460243653 100644 --- a/third_party/ijar/BUILD +++ b/third_party/ijar/BUILD @@ -30,7 +30,7 @@ cc_library( ] + select({ "//src:windows": [ "//src/main/cpp/util:errors", - "//src/main/cpp/util:file", + "//src/main/cpp/util:filesystem", "//src/main/cpp/util:logging", "//src/main/cpp/util:strings", ], @@ -59,7 +59,7 @@ cc_library( visibility = ["//visibility:private"], deps = [ "//src/main/cpp/util:errors", - "//src/main/cpp/util:file", + "//src/main/cpp/util:filesystem", "//src/main/cpp/util:logging", ], ) diff --git a/third_party/ijar/mapped_file_windows.cc b/third_party/ijar/mapped_file_windows.cc index 91bff719dd..1bcef8d7e0 100644 --- a/third_party/ijar/mapped_file_windows.cc +++ b/third_party/ijar/mapped_file_windows.cc @@ -18,8 +18,8 @@ #include <string> #include "src/main/cpp/util/errors.h" -#include "src/main/cpp/util/file_platform.h" #include "src/main/cpp/util/logging.h" +#include "src/main/cpp/util/path_platform.h" #include "src/main/cpp/util/strings.h" #include "third_party/ijar/mapped_file.h" diff --git a/third_party/ijar/platform_utils.cc b/third_party/ijar/platform_utils.cc index eeb4c40225..c73827d4b5 100644 --- a/third_party/ijar/platform_utils.cc +++ b/third_party/ijar/platform_utils.cc @@ -31,6 +31,8 @@ #include "src/main/cpp/util/file.h" #include "src/main/cpp/util/file_platform.h" #include "src/main/cpp/util/logging.h" +#include "src/main/cpp/util/path.h" +#include "src/main/cpp/util/path_platform.h" namespace devtools_ijar { diff --git a/tools/cpp/runfiles/BUILD b/tools/cpp/runfiles/BUILD index 7373b03e37..4a79245c04 100644 --- a/tools/cpp/runfiles/BUILD +++ b/tools/cpp/runfiles/BUILD @@ -35,7 +35,7 @@ cc_test( visibility = ["//visibility:public"], deps = [ ":runfiles", - "//src/main/cpp/util:file", + "//src/main/cpp/util:filesystem", "@com_google_googletest//:gtest_main", ], ) |