diff options
author | Karen Arutyunov <karen@codesynthesis.com> | 2018-03-18 00:33:28 +0300 |
---|---|---|
committer | Karen Arutyunov <karen@codesynthesis.com> | 2018-03-19 16:13:40 +0300 |
commit | 5d6ce25142dd4624f785ebf2ffe4cc2afb8d49e0 (patch) | |
tree | 47769c7b671d0b93a0ae96c103944da3fcdb62b6 | |
parent | 91e6f8b321fb470cfffa578dcd7f24669186604f (diff) |
Add support for cp builtin -p option
-rw-r--r-- | build2/test/script/builtin.cxx | 65 | ||||
-rw-r--r-- | doc/testscript.cli | 14 | ||||
-rw-r--r-- | tests/test/script/builtin/cp-dir/cp-file | 0 | ||||
-rw-r--r-- | tests/test/script/builtin/cp.test | 76 |
4 files changed, 136 insertions, 19 deletions
diff --git a/build2/test/script/builtin.cxx b/build2/test/script/builtin.cxx index 80954a1..91d5bf2 100644 --- a/build2/test/script/builtin.cxx +++ b/build2/test/script/builtin.cxx @@ -258,6 +258,7 @@ namespace build2 cpfile (scope& sp, const path& from, const path& to, bool overwrite, + bool attrs, bool cleanup, const function<error_record()>& fail) { @@ -265,10 +266,15 @@ namespace build2 { bool exists (file_exists (to)); - cpfile (from, to, - overwrite - ? cpflags::overwrite_permissions | cpflags::overwrite_content - : cpflags::none); + cpflags f ( + overwrite + ? cpflags::overwrite_permissions | cpflags::overwrite_content + : cpflags::none); + + if (attrs) + f |= cpflags::overwrite_permissions | cpflags::copy_timestamps; + + cpfile (from, to, f); if (!exists && cleanup) sp.clean ({cleanup_type::always, to}, true); @@ -288,6 +294,7 @@ namespace build2 static void cpdir (scope& sp, const dir_path& from, const dir_path& to, + bool attrs, bool cleanup, const function<error_record()>& fail) { @@ -308,10 +315,20 @@ namespace build2 cpdir (sp, path_cast<dir_path> (move (f)), path_cast<dir_path> (move (t)), + attrs, cleanup, fail); else - cpfile (sp, f, t, false, cleanup, fail); + cpfile (sp, f, t, false /* overwrite */, attrs, cleanup, fail); + } + + // Note that it is essential to copy timestamps and permissions after + // the directory content is copied. + // + if (attrs) + { + path_permissions (to, path_permissions (from)); + dir_time (to, dir_time (from)); } } catch (const system_error& e) @@ -321,10 +338,10 @@ namespace build2 } } - // cp [--no-cleanup] <src-file> <dst-file> - // cp [--no-cleanup] -R|-r <src-dir> <dst-dir> - // cp [--no-cleanup] <src-file>... <dst-dir>/ - // cp [--no-cleanup] -R|-r <src-path>... <dst-dir>/ + // cp [-p] [--no-cleanup] <src-file> <dst-file> + // cp [-p] [--no-cleanup] -R|-r <src-dir> <dst-dir> + // cp [-p] [--no-cleanup] <src-file>... <dst-dir>/ + // cp [-p] [--no-cleanup] -R|-r <src-path>... <dst-dir>/ // // Note: can be executed synchronously. // @@ -353,6 +370,7 @@ namespace build2 // Process options. // bool recursive (false); + bool attrs (false); bool cleanup (true); for (; i != e; ++i) { @@ -360,6 +378,8 @@ namespace build2 if (o == "-R" || o == "-r") recursive = true; + else if (o == "-p") + attrs = true; else if (o == "--no-cleanup") cleanup = false; else @@ -406,12 +426,19 @@ namespace build2 if (!recursive) // Synopsis 1: make a file copy at the specified path. // - cpfile (sp, src, dst, true, cleanup, fail); + cpfile (sp, + src, + dst, + true /* overwrite */, + attrs, + cleanup, + fail); else // Synopsis 2: make a directory copy at the specified path. // cpdir (sp, path_cast<dir_path> (src), path_cast<dir_path> (dst), + attrs, cleanup, fail); } @@ -429,13 +456,20 @@ namespace build2 cpdir (sp, path_cast<dir_path> (src), path_cast<dir_path> (dst / src.leaf ()), + attrs, cleanup, fail); else // Synopsis 3: copy a file into the specified directory. Also, // here we cover synopsis 4 for the source path being a file. // - cpfile (sp, src, dst / src.leaf (), true, cleanup, fail); + cpfile (sp, + src, + dst / src.leaf (), + true /* overwrite */, + attrs, + cleanup, + fail); } } @@ -612,10 +646,17 @@ namespace build2 if (dir) cpdir (sp, path_cast<dir_path> (target), path_cast<dir_path> (link), + false, cleanup, fail); else - cpfile (sp, target, link, false, cleanup, fail); + cpfile (sp, + target, + link, + false /* overwrite */, + true /* attrs */, + cleanup, + fail); } } } diff --git a/doc/testscript.cli b/doc/testscript.cli index 666d553..353850a 100644 --- a/doc/testscript.cli +++ b/doc/testscript.cli @@ -2241,10 +2241,10 @@ Read files in order and write their contents to \c{stdout}. Read from \h#builtins-cp|\c{cp}| \ -cp [--no-cleanup] <src-file> <dst-file> -cp [--no-cleanup] -R|-r <src-dir> <dst-dir> -cp [--no-cleanup] <src-file>... <dst-dir>/ -cp [--no-cleanup] -R|-r <src-path>... <dst-dir>/ +cp [-p] [--no-cleanup] <src-file> <dst-file> +cp [-p] [--no-cleanup] -R|-r <src-dir> <dst-dir> +cp [-p] [--no-cleanup] <src-file>... <dst-dir>/ +cp [-p] [--no-cleanup] -R|-r <src-path>... <dst-dir>/ \ Copy files and/or directories. The first two forms make a copy of a single @@ -2304,6 +2304,12 @@ files/directories does not exist or if the \i{dst-dir} filesystem entry does not exist or is not a directory. For a \i{src-path} directory \c{cp} also fails if the \i{dst-dir/src-name} filesystem entry already exists. +\dl| + +\li|\n\c{-p} + + Copy permissions as well as modification and access times.|| + Unless the --no-cleanup option is specified, newly created files and directories that are inside the script working directory are automatically registered for cleanup. diff --git a/tests/test/script/builtin/cp-dir/cp-file b/tests/test/script/builtin/cp-dir/cp-file new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/tests/test/script/builtin/cp-dir/cp-file diff --git a/tests/test/script/builtin/cp.test b/tests/test/script/builtin/cp.test index 4709459..6a26e35 100644 --- a/tests/test/script/builtin/cp.test +++ b/tests/test/script/builtin/cp.test @@ -103,9 +103,9 @@ { : existing : - : Test that copy over an existing file doesn't register cleanup. If it does - : then the file would be removed while leaving the embedded scope, and so - : the cleanup registered by the outer touch would fail. + : Test that copy over an existing file does not register cleanup. If it + : does then the file would be removed while leaving the embedded scope, + : and so the cleanup registered by the outer touch would fail. : $c <<EOI && $b +touch b @@ -304,3 +304,73 @@ EOI } } + +: attrs +: +if ($cxx.target.class != 'windows') +{ + fs = 's/.+ (\S+\s+\S+\s+\S+)\s+cp-file/\1/p' + ds = 's/.+ (\S+\s+\S+\s+\S+)\s+cp-dir/\1/p' + + : copy + : + { + : file + : + { + $c <<"EOI" && $b + ls -l $src_base/cp-dir | sed -n -e '$fs' | \ + set t; + + cp -p $src_base/cp-dir/cp-file ./; + ls -l | sed -n -e '$fs' >"\$t" + EOI + } + + : dir + : + { + $c <<"EOI" && $b + ls -l $src_base | sed -n -e '$ds' | \ + set t; + + cp -p -r $src_base/cp-dir ./; + ls -l | sed -n -e '$ds' >"\$t" + EOI + } + } + + : no-copy + : + { + : file + : + { + $c <<"EOI" && $b 2>>~%EOE% != 0 + ls -l $src_base/cp-dir | sed -n -e '$fs' | \ + set t; + + cp $src_base/cp-dir/cp-file ./; + ls -l | sed -n -e '$fs' >"\$t" + EOI + %.+ error: sed stdout doesn't match expected% + %.+ + EOE + } + + : dir + : + { + $c <<"EOI" && $b 2>>~%EOE% != 0 + ls -l $src_base | sed -n -e '$ds' | \ + set t; + + cp -r $src_base/cp-dir ./; + ls -l | sed -n -e '$ds' >"\$t" + EOI + %.+ error: sed stdout doesn't match expected% + %.+ + EOE + } + } +} |