@@ -756,6 +756,15 @@ def _file_equal(local_path: str | IO[Any] | None, remote_path: str) -> bool:
756756 return False
757757
758758
759+ def _remote_file_equal (remote_path_a : str , remote_path_b : str ) -> bool :
760+ for fact in [Sha1File , Md5File , Sha256File ]:
761+ sum_a = host .get_fact (fact , path = remote_path_a )
762+ sum_b = host .get_fact (fact , path = remote_path_b )
763+ if sum_a and sum_b :
764+ return sum_a == sum_b
765+ return False
766+
767+
759768@operation (
760769 # We don't (currently) cache the local state, so there's nothing we can
761770 # update to flag the local file as present.
@@ -1335,6 +1344,39 @@ def move(src: str, dest: str, overwrite=False):
13351344 yield StringCommand ("mv" , QuoteString (src ), QuoteString (dest ))
13361345
13371346
1347+ @operation ()
1348+ def copy (src : str , dest : str , overwrite = False ):
1349+ """
1350+ Copy remote file/directory/link into remote directory
1351+
1352+ + src: remote file/directory to copy
1353+ + dest: remote directory to copy `src` into
1354+ + overwrite: whether to overwrite dest, if present
1355+ """
1356+ src_is_dir = host .get_fact (Directory , src )
1357+ if not host .get_fact (File , src ) and not src_is_dir :
1358+ raise OperationError (f"src { src } does not exist" )
1359+
1360+ if not host .get_fact (Directory , dest ):
1361+ raise OperationError (f"dest { dest } is not an existing directory" )
1362+
1363+ dest_file_path = os .path .join (dest , os .path .basename (src ))
1364+ dest_file_exists = host .get_fact (File , dest_file_path )
1365+ if dest_file_exists and not overwrite :
1366+ if _remote_file_equal (src , dest_file_path ):
1367+ host .noop (f"{ dest_file_path } already exists" )
1368+ return
1369+ else :
1370+ raise OperationError (f"{ dest_file_path } already exists and is different than src" )
1371+
1372+ cp_cmd = ["cp -r" ]
1373+
1374+ if overwrite :
1375+ cp_cmd .append ("-f" )
1376+
1377+ yield StringCommand (* cp_cmd , QuoteString (src ), QuoteString (dest ))
1378+
1379+
13381380def _validate_path (path ):
13391381 try :
13401382 return os .fspath (path )
0 commit comments