summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkaizhangNV <149626564+kaizhangNV@users.noreply.github.com>2024-09-03 15:02:48 -0500
committerGitHub <noreply@github.com>2024-09-03 13:02:48 -0700
commit1673cf934b0871a6dd3b552a80913a5737fa3f61 (patch)
treec45d1431999abe32339922affda609ce33f7e78b
parent45e0eee31fb2e658f7e04771802cc18eb0b4e978 (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.cpp57
-rw-r--r--source/core/slang-io.h5
-rw-r--r--tools/slang-unit-test/unit-test-record-replay.cpp59
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;
}