aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--build2/test/script/runner.cxx47
-rw-r--r--build2/test/script/script24
-rw-r--r--build2/test/script/script.cxx11
-rw-r--r--tests/test/script/runner/cleanup.test100
4 files changed, 156 insertions, 26 deletions
diff --git a/build2/test/script/runner.cxx b/build2/test/script/runner.cxx
index 22ce67d..2174286 100644
--- a/build2/test/script/runner.cxx
+++ b/build2/test/script/runner.cxx
@@ -203,9 +203,22 @@ namespace build2
//
for (const auto& p: reverse_iterate (sp.cleanups))
{
+ // @@ Should we forbid removal of files and directories not inside
+ // the scope working directory? Inventing recursive removal makes
+ // cleanup a bit unsafe.
+ //
+
+ // Remove directory if exists and empty. Fail otherwise.
+ //
if (p.to_directory ())
{
dir_path d (path_cast<dir_path> (p));
+
+ // @@ If 'd' is a file then will fail with a diagnostics having no
+ // location info. Probably need to add an optional location
+ // parameter to rmdir() function. The same problem exists for a
+ // file cleanup when try to rmfile() directory instead of file.
+ //
rmdir_status r (rmdir (d, 2));
if (r != rmdir_status::success)
@@ -213,8 +226,40 @@ namespace build2
<< (r == rmdir_status::not_empty
? " is not empty"
: " does not exist");
+
+ continue;
}
- else if (rmfile (p, 2) == rmfile_status::not_exist)
+
+ // Remove directory recursively if not current. Fail otherwise.
+ // Recursive removal of non-existing directory is not an error.
+ //
+ // Note that if some file system entry of non-directory type exists
+ // with such a name it is not removed but the operation still
+ // succeeds. The removal of this entry can be handled at the time of
+ // the containing directory removed.
+ //
+ const string& s (p.string ());
+ size_t n (s.size ());
+
+ if (n >= 4 &&
+ string::traits_type::compare (
+ s.c_str () + n - 4, "/***", 4) == 0)
+ {
+ // Cast to uint16_t to avoid ambiguity with libbutl::rmdir_r().
+ //
+ rmdir_status r (
+ rmdir_r (p.directory (), true, static_cast<uint16_t> (2)));
+
+ if (r == rmdir_status::not_empty) // Directory is current.
+ fail (cl) << "registered for cleanup wildcard " << p
+ << " matches the current directory";
+
+ continue;
+ }
+
+ // Remove file if exists. Fail otherwise.
+ //
+ if (rmfile (p, 2) == rmfile_status::not_exist)
fail (cl) << "registered for cleanup file " << p
<< " does not exist";
}
diff --git a/build2/test/script/script b/build2/test/script/script
index 362f0df..c3b717f 100644
--- a/build2/test/script/script
+++ b/build2/test/script/script
@@ -171,8 +171,23 @@ namespace build2
optional<description> desc;
// Files and directories that must be automatically cleaned up when
- // the scope is left. If the path ends with a trailing slash, then it
- // is assumed to be to a directory, otherwise -- to a file.
+ // the scope is left. If the path contains '*' it is a wildcard. If the
+ // path is not a wildcard and ends with a trailing slash, then it is
+ // assumed to be to a directory, otherwise -- to a file. A directory
+ // must be empty by the time of removal,
+ //
+ // The supported wildcards:
+ //
+ // dir/*** - remove directory 'dir' with all files and sub-directories
+ // recursively. Removing non-existing 'dir' is not an error.
+ //
+ // The not yet supported wildcards:
+ //
+ // &dir/* - remove all immediate files of directory 'dir';
+ // &dir/*/ - remove all immediate sub-directories (must be empty);
+ // &dir/** - remove all files recursively;
+ // &dir/**/ - remove all sub-directories recursively (must be empty by
+ // the time of removal).
//
paths cleanups;
@@ -206,10 +221,7 @@ namespace build2
// Register path for cleanup. Suppress duplicates.
//
void
- clean (const path& p);
-
- void
- clean (path&& p);
+ clean (path p);
public:
virtual
diff --git a/build2/test/script/script.cxx b/build2/test/script/script.cxx
index f1dab63..058720a 100644
--- a/build2/test/script/script.cxx
+++ b/build2/test/script/script.cxx
@@ -291,16 +291,7 @@ namespace build2
// command
//
void scope::
- clean (const path& p)
- {
- using std::find; // Hidden by scope::find().
-
- if (find (cleanups.begin (), cleanups.end (), p) == cleanups.end ())
- cleanups.emplace_back (p);
- }
-
- void scope::
- clean (path&& p)
+ clean (path p)
{
using std::find; // Hidden by scope::find().
diff --git a/tests/test/script/runner/cleanup.test b/tests/test/script/runner/cleanup.test
index 9a660d5..61a66b4 100644
--- a/tests/test/script/runner/cleanup.test
+++ b/tests/test/script/runner/cleanup.test
@@ -11,20 +11,102 @@ using test
EOI
b = $build.driver -q --no-column --buildfile - <"./: test{testscript}" \
- &test/ test
+ &test/*** test
c = cat >>>testscript
-$* -f a &a # file
-$* -d a &a/ # dir1
-$* -d a/b &a/ &a/b/ # dir2
-$* -d a/b -f a/b/c &a/ &a/b/ &a/b/c # file-dir
-$* -f a &a &a # file-dup
-$* -d a/b &a/ &a/b/ &a/b/../b/ # dir-dup
+# Valid cleanups.
+#
+# @@ TODO: $c <"$* -f a &a" && $b
+#
+: files
+:
+$c <"$* -f a &a";
+$b
+
+: dir1
+:
+$c <"$* -d a &a/";
+$b
+
+: dir2
+$c <"$* -d a/b &a/ &a/b/";
+$b
+
+: file-dir
+$c <"$* -d a/b -f a/b/c &a/ &a/b/ &a/b/c";
+$b
+
+: wildcard1
+$c <"$* -d a/b -f a/b/c &a/***";
+$b
+
+: wildcard2
+:
+$c <"$* &a/***";
+$b
+
+: file-dup
+$c <"$* -f a &a &a";
+$b
-# <test-id>
+: dir-dup
+$c <"$* -d a/b &a/ &a/b/ &a/b/../b/";
+$b
+
+# Invalid cleanups.
#
-# @@ TODO: $c <"$* &a/" && $b 2>>EOE
+: file-not-exists
+:
+$c <"$* &a";
+$b 2>>EOE != 0
+testscript:1: error: registered for cleanup file test/1/a does not exist
+EOE
+
+: dir-not-exists
+:
$c <"$* &a/";
$b 2>>EOE != 0
testscript:1: error: registered for cleanup directory test/1/a/ does not exist
EOE
+
+: dir-not-empty1
+:
+$c <"$* -d a/b -f a/b/c";
+$b 2>>EOE != 0
+testscript:1: error: registered for cleanup directory test/1/ is not empty
+EOE
+
+: dir-not-empty2
+:
+$c <"$* -d a/b &a/b/";
+$b 2>>EOE != 0
+testscript:1: error: registered for cleanup directory test/1/ is not empty
+EOE
+
+: dir-not-empty3
+:
+$c <"$* -d a/b &a/b/ &a/";
+$b 2>>EOE != 0
+testscript:1: error: registered for cleanup directory test/1/a/ is not empty
+EOE
+
+: dir-not-empty4
+:
+$c <"$* -f a &a/***";
+$b 2>>EOE != 0
+testscript:1: error: registered for cleanup directory test/1/ is not empty
+EOE
+
+: not-file
+:
+$c <"$* -d a &a";
+$b 2>>EOE != 0
+error: unable to remove file test/1/a: Is a directory
+EOE
+
+: not-dir1
+:
+$c <"$* -f a &a/";
+$b 2>>EOE != 0
+error: unable to remove directory test/1/a/: Not a directory
+EOE