Skip to content

Commit 9809645

Browse files
author
Pan
committed
Fix ssh2 client sftp push/pull with absolute paths
1 parent 3c50a7b commit 9809645

File tree

2 files changed

+47
-28
lines changed

2 files changed

+47
-28
lines changed

pssh/ssh2_client.py

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -396,11 +396,13 @@ def copy_file(self, local_file, remote_file, recurse=False,
396396
:raises: :py:class:`OSError` on local OS errors like permission denied
397397
"""
398398
sftp = self._make_sftp() if sftp is None else sftp
399+
# import ipdb; ipdb.set_trace()
399400
if os.path.isdir(local_file) and recurse:
400401
return self._copy_dir(local_file, remote_file, sftp)
401402
elif os.path.isdir(local_file) and not recurse:
402403
raise ValueError("Recurse must be true if local_file is a "
403404
"directory.")
405+
# import ipdb; ipdb.set_trace()
404406
destination = self._remote_paths_split(remote_file)
405407
if destination is not None:
406408
try:
@@ -433,7 +435,7 @@ def sftp_put(self, sftp, local_file, remote_file):
433435
logger.error(msg, remote_file, ex)
434436
raise SFTPIOError(msg, remote_file, ex)
435437

436-
def mkdir(self, sftp, directory, parent_path=None):
438+
def mkdir(self, sftp, directory, _parent_path=None):
437439
"""Make directory via SFTP channel.
438440
439441
Parent paths in the directory are created if they do not exist.
@@ -445,21 +447,32 @@ def mkdir(self, sftp, directory, parent_path=None):
445447
446448
Catches and logs at error level remote IOErrors on creating directory.
447449
"""
450+
# import ipdb; ipdb.set_trace()
451+
# if _parent_path is None and directory.startswith('/'):
452+
# directory = self._eagain(sftp.realpath, directory)
448453
try:
449-
_parent_path, sub_dirs = directory.split('/', 1)
454+
_dir, sub_dirs = directory.split('/', 1)
450455
except ValueError:
451-
_parent_path = directory.split('/', 1)[0]
456+
_dir = directory.split('/', 1)[0]
452457
sub_dirs = None
453-
_directory = _parent_path if parent_path is None else \
454-
'/'.join([parent_path, _parent_path])
458+
if not _dir and directory.startswith('/'):
459+
try:
460+
_dir, sub_dirs = sub_dirs.split(os.path.sep, 1)
461+
except ValueError:
462+
return True
463+
if _parent_path is not None:
464+
_dir = '/'.join((_parent_path, _dir))
455465
try:
456-
self._eagain(sftp.stat, _directory)
466+
self._eagain(sftp.stat, _dir)
457467
except SFTPHandleError:
458-
self._mkdir(sftp, _directory)
468+
self._mkdir(sftp, _dir)
459469
if sub_dirs is not None:
460-
_parent_path = _parent_path if parent_path is None else \
461-
'/'.join([parent_path, _parent_path])
462-
return self.mkdir(sftp, sub_dirs, parent_path=_parent_path)
470+
# import ipdb; ipdb.set_trace()c
471+
if directory.startswith('/'):
472+
_dir = ''.join(('/', _dir))
473+
# _parent_path = _dir if _parent_path is None else \
474+
# '/'.join([_parent_path, _dir])
475+
return self.mkdir(sftp, sub_dirs, _parent_path=_dir)
463476

464477
def _copy_dir(self, local_dir, remote_dir, sftp):
465478
"""Call copy_file on every file in the specified directory, copying
@@ -496,6 +509,7 @@ def copy_remote_file(self, remote_file, local_file, recurse=False,
496509
:raises: :py:class:`IOError` on local file IO errors
497510
:raises: :py:class:`OSError` on local OS errors like permission denied
498511
"""
512+
# import ipdb; ipdb.set_trace()
499513
sftp = self._make_sftp() if sftp is None else sftp
500514
try:
501515
self._eagain(sftp.stat, remote_file)
@@ -585,6 +599,6 @@ def _remote_paths_split(self, file_path):
585599
if _dir][:-1])
586600
except IndexError:
587601
return
588-
if destination == '':
589-
return
602+
if file_path.startswith('/') or destination == '':
603+
return '/' + destination
590604
return destination

tests/test_pssh_ssh2_client.py

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -319,7 +319,9 @@ def test_pssh_client_directory(self):
319319
test_file_data = 'test'
320320
local_test_path = 'directory_test'
321321
remote_test_path = 'directory_test_copied'
322-
remote_test_path_abs = os.path.expanduser('~/' + remote_test_path)
322+
dir_name = os.path.dirname(__file__)
323+
remote_test_path_abs = os.sep.join(
324+
(dir_name, remote_test_path))
323325
for path in [local_test_path, remote_test_path_abs]:
324326
try:
325327
shutil.rmtree(path)
@@ -334,23 +336,25 @@ def test_pssh_client_directory(self):
334336
local_file_path = os.path.join(local_file_path_dir, 'foo' + str(i))
335337
remote_file_path = os.path.join(
336338
remote_test_path, 'sub_dir1', 'sub_dir2', 'dir_foo' + str(i), 'foo' + str(i))
337-
remote_file_paths.append(os.path.expanduser('~/' + remote_file_path))
339+
remote_file_paths.append(
340+
os.sep.join((os.path.dirname(__file__), remote_file_path)))
338341
test_file = open(local_file_path, 'w')
339342
test_file.write(test_file_data)
340343
test_file.close()
341-
cmds = self.client.copy_file(local_test_path, remote_test_path, recurse=True)
344+
cmds = self.client.copy_file(local_test_path, remote_test_path_abs, recurse=True)
342345
gevent.joinall(cmds, raise_error=True)
343346
for path in remote_file_paths:
344347
self.assertTrue(os.path.isfile(path))
345348
shutil.rmtree(local_test_path)
346-
shutil.rmtree(remote_test_path_abs)
349+
shutil.rmtree(os.sep.join((os.path.dirname(__file__), remote_test_path)))
347350

348351
def test_pssh_client_copy_file_failure(self):
349352
"""Test failure scenarios of file copy"""
350353
test_file_data = 'test'
351354
local_test_path = 'directory_test'
352355
remote_test_path = 'directory_test_copied'
353-
remote_test_path_abs = os.path.expanduser('~/' + remote_test_path)
356+
dir_name = os.path.dirname(__file__)
357+
remote_test_path_abs = os.sep.join((dir_name, remote_test_path))
354358
for path in [local_test_path, remote_test_path_abs]:
355359
mask = int('0700') if sys.version_info <= (2,) else 0o700
356360
if os.path.isdir(path):
@@ -367,32 +371,32 @@ def test_pssh_client_copy_file_failure(self):
367371
os.mkdir(remote_test_path_abs)
368372
local_file_path = os.path.join(local_test_path, 'test_file')
369373
remote_file_path = os.path.join(remote_test_path, 'test_file')
370-
remote_file_path_abs = os.path.expanduser('~/' + remote_file_path)
374+
remote_test_path_abs = os.sep.join((dir_name, remote_test_path))
371375
test_file = open(local_file_path, 'w')
372376
test_file.write('testing\n')
373377
test_file.close()
374378
# Permission errors on writing into dir
375379
mask = int('0111') if sys.version_info <= (2,) else 0o111
376380
os.chmod(remote_test_path_abs, mask)
377-
cmds = self.client.copy_file(local_test_path, remote_test_path, recurse=True)
381+
cmds = self.client.copy_file(local_test_path, remote_test_path_abs, recurse=True)
378382
try:
379383
gevent.joinall(cmds, raise_error=True)
380384
raise Exception("Expected SFTPError exception")
381385
except SFTPError:
382386
pass
383-
self.assertFalse(os.path.isfile(remote_file_path_abs))
387+
self.assertFalse(os.path.isfile(remote_test_path_abs))
384388
# Create directory tree failure test
385389
local_file_path = os.path.join(local_test_path, 'test_file')
386390
remote_file_path = os.path.join(remote_test_path, 'test_dir', 'test_file')
387-
remote_file_path_abs = os.path.expanduser('~/' + remote_file_path)
388-
cmds = self.client.copy_file(local_file_path, remote_file_path, recurse=True)
391+
remote_test_path_abs = os.sep.join((dir_name, remote_test_path))
392+
cmds = self.client.copy_file(local_file_path, remote_test_path_abs, recurse=True)
389393
try:
390394
gevent.joinall(cmds, raise_error=True)
391395
raise Exception("Expected SFTPError exception on creating remote "
392396
"directory")
393397
except SFTPError:
394398
pass
395-
self.assertFalse(os.path.isfile(remote_file_path_abs))
399+
self.assertFalse(os.path.isfile(remote_test_path_abs))
396400
mask = int('0600') if sys.version_info <= (2,) else 0o600
397401
os.chmod(remote_test_path_abs, mask)
398402
for path in [local_test_path, remote_test_path_abs]:
@@ -406,9 +410,10 @@ def test_pssh_copy_remote_file_failure(self):
406410
def test_pssh_copy_remote_file(self):
407411
"""Test parallel copy file to local host"""
408412
test_file_data = 'test'
409-
local_test_path = os.path.expanduser('~/' + 'directory_test_local_remote_copied')
413+
dir_name = os.path.dirname(__file__)
414+
local_test_path = os.sep.join((dir_name, 'directory_test_local_remote_copied'))
410415
remote_test_path = 'directory_test_remote_copy'
411-
remote_test_path_abs = os.path.expanduser('~/' + remote_test_path)
416+
remote_test_path_abs = os.sep.join((dir_name, remote_test_path))
412417
local_copied_dir = '_'.join([local_test_path, self.host])
413418
new_local_copied_dir = '.'.join([local_test_path, self.host])
414419
for path in [local_test_path, remote_test_path_abs, local_copied_dir,
@@ -434,9 +439,9 @@ def test_pssh_copy_remote_file(self):
434439
test_file = open(remote_file_path, 'w')
435440
test_file.write(test_file_data)
436441
test_file.close()
437-
cmds = self.client.copy_remote_file(remote_test_path, local_test_path)
442+
cmds = self.client.copy_remote_file(remote_test_path_abs, local_test_path)
438443
self.assertRaises(ValueError, gevent.joinall, cmds, raise_error=True)
439-
cmds = self.client.copy_remote_file(remote_test_path, local_test_path,
444+
cmds = self.client.copy_remote_file(remote_test_path_abs, local_test_path,
440445
recurse=True)
441446
gevent.joinall(cmds, raise_error=True)
442447
try:
@@ -447,7 +452,7 @@ def test_pssh_copy_remote_file(self):
447452
shutil.rmtree(remote_test_path_abs)
448453
finally:
449454
shutil.rmtree(local_copied_dir)
450-
cmds = self.client.copy_remote_file(remote_test_path, local_test_path,
455+
cmds = self.client.copy_remote_file(remote_test_path_abs, local_test_path,
451456
suffix_separator='.', recurse=True)
452457
gevent.joinall(cmds, raise_error=True)
453458
new_local_copied_dir = '.'.join([local_test_path, self.host])

0 commit comments

Comments
 (0)