Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions Changelog.rst
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
Change Log
============

1.12.2
++++++
1.12.2 (unreleased)
+++++++++++++++++++

Fixes
------

* `ParallelSSHClient.copy_file` with recurse enabled and absolute destination path would create empty directory in home directory of user - #197.
* `ParallelSSHClient.copy_file` and `scp_recv` with recurse enabled would not create remote directories when copying empty local directories.
* `ParallelSSHClient.scp_send` would require SFTP when recurse is off and remote destination path contains directory - #157.

1.12.1
++++++
Expand Down
17 changes: 9 additions & 8 deletions pssh/clients/native/single.py
Original file line number Diff line number Diff line change
Expand Up @@ -484,8 +484,8 @@ def scp_recv(self, remote_file, local_file, recurse=False, sftp=None,
:raises: :py:class:`IOError` on local file IO errors.
:raises: :py:class:`OSError` on local OS errors like permission denied.
"""
sftp = self._make_sftp() if (sftp is None and recurse) else sftp
if recurse:
sftp = self._make_sftp() if sftp is None else sftp
try:
self._eagain(sftp.stat, remote_file)
except (SFTPHandleError, SFTPProtocolError):
Expand Down Expand Up @@ -575,13 +575,14 @@ def scp_send(self, local_file, remote_file, recurse=False, sftp=None):
elif os.path.isdir(local_file) and not recurse:
raise ValueError("Recurse must be True if local_file is a "
"directory.")
destination = self._remote_paths_split(remote_file)
if destination is not None:
sftp = self._make_sftp() if sftp is None else sftp
try:
self._eagain(sftp.stat, destination)
except (SFTPHandleError, SFTPProtocolError):
self.mkdir(sftp, destination)
if recurse:
destination = self._remote_paths_split(remote_file)
if destination is not None:
sftp = self._make_sftp() if sftp is None else sftp
try:
self._eagain(sftp.stat, destination)
except (SFTPHandleError, SFTPProtocolError):
self.mkdir(sftp, destination)
self._scp_send(local_file, remote_file)
logger.info("SCP local file %s to remote destination %s:%s",
local_file, self.host, remote_file)
Expand Down
29 changes: 28 additions & 1 deletion tests/native/test_parallel_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -1319,6 +1319,10 @@ def test_file_read_no_timeout(self):
self.assertListEqual(_contents, _out)

def test_scp_send_dir(self):
"""
Attempting to copy into a non-existent remote directory via scp_send()
without recurse=True should raise an SCPError.
"""
test_file_data = 'test'
local_filename = 'test_file'
remote_test_dir, remote_filepath = 'remote_test_dir', 'test_file_copy'
Expand All @@ -1330,7 +1334,30 @@ def test_scp_send_dir(self):
try:
cmds = self.client.scp_send(local_filename, remote_filename)
joinall(cmds, raise_error=True)
time.sleep(.2)
except Exception as ex:
self.assertIsInstance(ex, SCPError)
finally:
try:
os.unlink(local_filename)
except OSError:
pass
try:
shutil.rmtree(remote_test_dir_abspath)
except OSError:
pass

def test_scp_send_dir_recurse(self):
test_file_data = 'test'
local_filename = 'test_file'
remote_test_dir, remote_filepath = 'remote_test_dir', 'test_file_copy'
with open(local_filename, 'w') as file_h:
file_h.writelines([test_file_data + os.linesep])
remote_filename = os.path.sep.join([remote_test_dir, remote_filepath])
remote_file_abspath = os.path.expanduser('~/' + remote_filename)
remote_test_dir_abspath = os.path.expanduser('~/' + remote_test_dir)
try:
cmds = self.client.scp_send(local_filename, remote_filename, recurse=True)
joinall(cmds, raise_error=True)
self.assertTrue(os.path.isdir(remote_test_dir_abspath))
self.assertTrue(os.path.isfile(remote_file_abspath))
remote_file_data = open(remote_file_abspath, 'r').read()
Expand Down