diff options
-rw-r--r-- | build2/test/script/runner.cxx | 47 | ||||
-rw-r--r-- | build2/test/script/script | 24 | ||||
-rw-r--r-- | build2/test/script/script.cxx | 11 | ||||
-rw-r--r-- | tests/test/script/runner/cleanup.test | 100 |
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 |