@@ -298,14 +298,14 @@ def _mkdir(self, sftp, directory):
298298
299299 def mkdir (self , sftp , directory ):
300300 """Make directory via SFTP channel.
301-
301+
302302 Parent paths in the directory are created if they do not exist.
303-
303+
304304 :param sftp: SFTP client object
305305 :type sftp: :mod:`paramiko.SFTPClient`
306306 :param directory: Remote directory to create
307307 :type directory: str
308-
308+
309309 Catches and logs at error level remote IOErrors on creating directory.
310310 """
311311 try :
@@ -360,7 +360,7 @@ def copy_file(self, local_file, remote_file, recurse=False):
360360 raise ValueError ("Recurse must be true if local_file is a "
361361 "directory." )
362362 sftp = self ._make_sftp ()
363- destination = self ._parent_path_split (remote_file )
363+ destination = self ._parent_paths_split (remote_file )
364364 try :
365365 sftp .stat (destination )
366366 except IOError :
@@ -375,70 +375,71 @@ def copy_file(self, local_file, remote_file, recurse=False):
375375 logger .info ("Copied local file %s to remote destination %s:%s" ,
376376 local_file , self .host , remote_file )
377377
378- def _copy_dir_to_local (self , remote_dir , local_dir ):
379- """Copies the remote directory to the local host."""
380- sftp = self ._make_sftp ()
381- file_list = sftp .listdir (remote_dir )
382- for file_name in file_list :
383- remote_path = os .path .join (remote_dir , file_name )
384- local_path = os .path .join (local_dir , file_name )
385- self .copy_file_to_local (remote_path , local_path , recurse = True )
386-
387- def copy_file_to_local (self , remote_file , local_file , recurse = False ):
378+ def copy_remote_file (self , remote_file , local_file , recurse = False ,
379+ sftp = None ):
388380 """Copy remote file to local host via SFTP/SCP
389381
390- Copy is done natively using SFTP/SCP version 2 protocol , no scp command \
382+ Copy is done natively using SFTP/SCP version 2, no scp command \
391383 is used or required.
392384
393- :param remote_file: Remote filepath to copy the file from.
385+ :param remote_file: Remote filepath to copy from
394386 :type remote_file: str
395- :param local_file: Local filepath where the file will be copied.
387+ :param local_file: Local filepath where file(s) will be copied to
396388 :type local_file: str
397- :param recurse: Whether or not to recursively copy directories.
389+ :param recurse: Whether or not to recursively copy directories
398390 :type recurse: bool
399391
400392 :raises: :mod:`ValueError` when a directory is supplied to remote_file \
401393 and recurse is not set
402- :raises: :mod:`OSError ` on OS errors creating directories or file
403- :raises: :mod:`IOError ` on IO errors creating directories or file
394+ :raises: :mod:`IOError ` on I/O errors creating directories or file
395+ :raises: :mod:`OSError ` on OS errors like permission denied
404396 """
405- sftp = self ._make_sftp ()
397+ sftp = self ._make_sftp () if not sftp else sftp
406398 try :
407- sftp .listdir (remote_file )
408- except (OSError , IOError ):
409- remote_dir_exists = False
399+ file_list = sftp .listdir (remote_file )
400+ except IOError :
401+ # remote_file is not dir
402+ pass
410403 else :
411- remote_dir_exists = True
412- if remote_dir_exists and recurse :
413- return self ._copy_dir_to_local (remote_file , local_file )
414- elif remote_dir_exists and not recurse :
415- raise ValueError ("Recurse must be true if remote_file is a "
416- "directory." )
417- destination = self ._parent_path_split (local_file )
404+ if not recurse :
405+ raise ValueError ("Recurse must be true if remote_file is a "
406+ "directory." )
407+ return self ._copy_remote_dir (file_list , remote_file ,
408+ local_file , sftp )
409+ destination = self ._parent_paths_split (local_file )
418410 self ._make_local_dir (destination )
419411 try :
420412 sftp .get (remote_file , local_file )
421- except Exception , error :
422- logger .error ("Error occured copying file %s from remote destination %s:%s - %s" ,
413+ except Exception as error :
414+ logger .error ("Error occured copying file %s from remote destination"
415+ " %s:%s - %s" ,
423416 local_file , self .host , remote_file , error )
424- raise error
425- else :
426- logger .info ("Copied local file %s from remote destination %s:%s" ,
427- local_file , self .host , remote_file )
417+ raise
418+ logger .info ("Copied local file %s from remote destination %s:%s" ,
419+ local_file , self .host , remote_file )
420+
421+ def _copy_remote_dir (self , file_list , remote_dir , local_dir , sftp ):
422+ for file_name in file_list :
423+ remote_path = os .path .join (remote_dir , file_name )
424+ local_path = os .path .join (local_dir , file_name )
425+ self .copy_remote_file (remote_path , local_path , sftp = sftp ,
426+ recurse = True )
428427
429428 def _make_local_dir (self , dirpath ):
430- if not os .path .exists (dirpath ):
431- try :
432- os .makedirs (dirpath )
433- except OSError :
434- logger .error ("Unable to create local directory structure for "
435- "directory %s" , dirpath )
436- raise
429+ if os .path .exists (dirpath ):
430+ return
431+ try :
432+ os .makedirs (dirpath )
433+ except OSError :
434+ logger .error ("Unable to create local directory structure for "
435+ "directory %s" , dirpath )
436+ raise
437437
438- def _parent_path_split (self , file_path ):
438+ def _parent_paths_split (self , file_path ):
439439 try :
440- destination = [_dir for _dir in file_path .split (os .path .sep )
441- if _dir ][:- 1 ][0 ]
440+ destination = os .path .sep .join (
441+ [_dir for _dir in file_path .split (os .path .sep )
442+ if _dir ][:- 1 ])
442443 except IndexError :
443444 destination = ''
444445 if file_path .startswith (os .path .sep ) or not destination :
0 commit comments