diff options
| author | kaizhangNV <149626564+kaizhangNV@users.noreply.github.com> | 2024-09-03 15:02:48 -0500 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-09-03 13:02:48 -0700 |
| commit | 1673cf934b0871a6dd3b552a80913a5737fa3f61 (patch) | |
| tree | c45d1431999abe32339922affda609ce33f7e78b | |
| parent | 45e0eee31fb2e658f7e04771802cc18eb0b4e978 (diff) | |
Add Path::removeNonEmpty() to remove non-empty dir (#4984)
We've implemented a function in slang-record-replay unit test
to remove the non-empty directory, now move this function into
slang `Path` namespace to make this function as an utility.
Close issue #4916
| -rw-r--r-- | source/core/slang-io.cpp | 57 | ||||
| -rw-r--r-- | source/core/slang-io.h | 5 | ||||
| -rw-r--r-- | tools/slang-unit-test/unit-test-record-replay.cpp | 59 |
3 files changed, 67 insertions, 54 deletions
diff --git a/source/core/slang-io.cpp b/source/core/slang-io.cpp index ffbb5fa98..dd390fc28 100644 --- a/source/core/slang-io.cpp +++ b/source/core/slang-io.cpp @@ -17,6 +17,7 @@ #ifdef _WIN32 # include <direct.h> # include <windows.h> +# include <shellapi.h> #endif #if defined(__linux__) || defined(__CYGWIN__) || SLANG_APPLE_FAMILY @@ -27,6 +28,7 @@ # include <dirent.h> # include <sys/stat.h> # include <sys/file.h> +# include <ftw.h> // for nftw #endif #if SLANG_APPLE_FAMILY @@ -777,6 +779,61 @@ namespace Slang #endif } + /* static */SlangResult Path::removeNonEmpty(const String& path) + { + if (File::exists(path) == false) + { + return SLANG_OK; + } + + StringBuilder msgBuilder; + // Path::remove() doesn't support remove a non-empty directory, so we need to implement + // a simple function to remove the directory recursively. +#ifdef _WIN32 + // https://learn.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-shfileoperationa + // Note: the fromPath requires a double-null-terminated string. + String newPath = path; + newPath.append('\0'); + SHFILEOPSTRUCTA file_op = { + NULL, + FO_DELETE, + newPath.begin(), + nullptr, + FOF_NOCONFIRMATION | + FOF_NOERRORUI | + FOF_SILENT, + false, + 0, + nullptr }; + int ret = SHFileOperationA(&file_op); + if (ret) + { + return SLANG_FAIL; + } +#else + auto unlink_cb = [](const char* fpath, const struct stat* sb, int typeflag, struct FTW* ftwbuf) -> int + { + SLANG_UNUSED(sb) + SLANG_UNUSED(typeflag) + SLANG_UNUSED(ftwbuf) + int rv = ::remove(fpath); + if (rv) + { + perror(fpath); + } + return rv; + }; + // https://linux.die.net/man/3/nftw + int ret = ::nftw(path.begin(), unlink_cb, 64, FTW_DEPTH | FTW_PHYS); + if (ret) + { + return SLANG_FAIL; + } +#endif + + return SLANG_OK; + } + #if defined(_WIN32) /* static */SlangResult Path::find(const String& directoryPath, const char* pattern, Visitor* visitor) { diff --git a/source/core/slang-io.h b/source/core/slang-io.h index 763907c98..676635a36 100644 --- a/source/core/slang-io.h +++ b/source/core/slang-io.h @@ -217,6 +217,11 @@ namespace Slang /// @return SLANG_OK if file or directory is removed static SlangResult remove(const String& path); + /// Remove a file or directory at specified path. The directory can be non-empty. + /// @param path + /// @return SLANG_OK if file or directory is removed + static SlangResult removeNonEmpty(const String& path); + static bool equals(String path1, String path2); /// Turn `path` into a relative path from base. diff --git a/tools/slang-unit-test/unit-test-record-replay.cpp b/tools/slang-unit-test/unit-test-record-replay.cpp index d775e1421..33bbab0c3 100644 --- a/tools/slang-unit-test/unit-test-record-replay.cpp +++ b/tools/slang-unit-test/unit-test-record-replay.cpp @@ -9,13 +9,6 @@ #include "tools/unit-test/slang-unit-test.h" -#ifdef _WIN32 -#include <windows.h> -#include <shellapi.h> -#else -#include <ftw.h> -#endif - #include <chrono> #include <thread> @@ -355,55 +348,13 @@ static SlangResult resultCompare(List<entryHashInfo> const& expectHashes, List<e static SlangResult cleanupRecordFiles() { - if (File::exists("slang-record") == false) - { - return SLANG_OK; - } - - StringBuilder msgBuilder; - // Path::remove() doesn't support remove a non-empty directory, so we need to implement - // a simple function to remove the directory recursively. -#ifdef _WIN32 - // https://learn.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-shfileoperationa - SHFILEOPSTRUCTA file_op = { - NULL, - FO_DELETE, - "slang-record", - "", - FOF_NOCONFIRMATION | - FOF_NOERRORUI | - FOF_SILENT, - false, - 0, - "" }; - int ret = SHFileOperationA(&file_op); - if (ret) - { - msgBuilder << "fail to remove 'slang-record' dir, error: " << ret << "\n"; - getTestReporter()->message(TestMessageType::TestFailure, msgBuilder.toString().getBuffer()); - return SLANG_FAIL; - } -#else - auto unlink_cb = [](const char* fpath, const struct stat* sb, int typeflag, struct FTW* ftwbuf) -> int - { - int rv = ::remove(fpath); - if (rv) - { - perror(fpath); - } - return rv; - }; - // https://linux.die.net/man/3/nftw - int ret = nftw("slang-record", unlink_cb, 64, FTW_DEPTH | FTW_PHYS); - if (ret) + SlangResult res = Path::removeNonEmpty("slang-record"); + if (SLANG_FAILED(res)) { - msgBuilder << "fail to remove 'slang-record' dir, error: " << ret << ", " << strerror(errno) << "\n"; - getTestReporter()->message(TestMessageType::TestFailure, msgBuilder.toString().getBuffer()); - return SLANG_FAIL; + getTestReporter()->message(TestMessageType::TestFailure, "Failed to remove 'slang-record' directory\n"); } -#endif - return SLANG_OK; + return res; } static SlangResult runTest(UnitTestContext* context, const char* testName) @@ -427,7 +378,7 @@ static SlangResult runTest(UnitTestContext* context, const char* testName) } error: - cleanupRecordFiles(); + res = cleanupRecordFiles(); return res; } |
