sshUtils.py

Go to the documentation of this file.
00001 ##
00002 # 
00003 # SSH support for win32 development to spoof accessing server based Linux resources.
00004 # 
00005 
00006 __copyright__ = """\
00007 (c). Copyright 1990-2008, Vyper Logix Corp., All Rights Reserved.
00008 
00009 Published under Creative Commons License 
00010 (http://creativecommons.org/licenses/by-nc/3.0/) 
00011 restricted to non-commercial educational use only., 
00012 
00013 See also: http://www.VyperLogix.com and http://www.pypi.info for details.
00014 
00015 THE AUTHOR VYPER LOGIX CORP DISCLAIMS ALL WARRANTIES WITH REGARD TO
00016 THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
00017 FITNESS, IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL,
00018 INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
00019 FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
00020 NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
00021 WITH THE USE OR PERFORMANCE OF THIS SOFTWARE !
00022 
00023 USE AT YOUR OWN RISK.
00024 """
00025 
00026 import os
00027 import sys
00028 import traceback
00029 
00030 from vyperlogix.classes.CooperativeClass import Cooperative
00031 from vyperlogix.misc import ObjectTypeName
00032 from vyperlogix.misc.ObjectTypeName import __typeName as ObjectTypeName__typeName
00033 from vyperlogix.misc import _utils
00034 from vyperlogix import misc
00035 
00036 try:
00037     import paramiko
00038 except ImportError, details:
00039     print 'WARNING due to "%s".' % str(details)
00040 
00041 try:
00042     from cStringIO import StringIO
00043 except ImportError:
00044     from StringIO import StringIO
00045     
00046 from vyperlogix.hash import lists
00047     
00048 def calcXferRate(xfer_rate):
00049     xfer_factor = 1
00050     xfer_rate_calc = xfer_rate/1024
00051     xfer_rate_fmt = '%s KB/sec' % ('%-4.2f' % xfer_rate_calc).strip()
00052     if (xfer_rate_calc > 1024):
00053         xfer_factor = 1024
00054         xfer_rate_calc = xfer_rate/(1024*xfer_factor)
00055         xfer_rate_fmt = '%s MB/sec' % ('%-4.2f' % xfer_rate_calc).strip()
00056     return lists.HashedLists2({'xfer_rate':xfer_rate,'xfer_factor':xfer_factor,'xfer_rate_fmt':xfer_rate_fmt})
00057 
00058 def giveXferStatus(iBytes,iTotal,xfer_rate,secs):
00059     if (iTotal > 0) and (xfer_rate > 0):
00060         xfer_rate_calc = calcXferRate(xfer_rate)
00061         print '(%2.2f%%) %s %s of %s in %4.2f seconds.' % ((float(iBytes)/float(iTotal))*100.0,xfer_rate_calc['xfer_rate_fmt'],iBytes,iTotal,((iTotal-iBytes)/(xfer_rate*xfer_rate_calc['xfer_factor'])))
00062 
00063 class SSHConnection(Cooperative):
00064     def __init__(self,hostname='',port=22,username='',password='',isLazy=False):
00065         self.__lastError__ = StringIO()
00066         self.__hostname__ = hostname
00067         self.__port__ = port
00068         self.__username__ = username
00069         self.__password__ = password
00070         self.__transport__ = None
00071         self.__sftp__ = None
00072         self.__sep__ = '/'
00073         if (not isLazy):
00074             self.ssh_connect_client()
00075         pass
00076     
00077     def __repr__(self):
00078         c = ObjectTypeName__typeName(self)
00079         return '%s(hostname="%s",port=%s,username="%s",password="...")' % (c,self.hostname,self.port,self.username)
00080 
00081     def __str__(self):
00082         return '%s@%s:%s' % (self.username,self.hostname,self.port)
00083 
00084     def sep():
00085         doc = "seperator for host file names"
00086         def fget(self):
00087             return self.__sep__
00088         return locals()
00089     sep = property(**sep())
00090     
00091     def transport():
00092         doc = "transport"
00093         def fget(self):
00094             return self.__transport__
00095         return locals()
00096     transport = property(**transport())
00097     
00098     def sftp():
00099         doc = "sftp"
00100         def fget(self):
00101             if (self.__sftp__ is None):
00102                 self.ssh_connect_client()
00103             return self.__sftp__
00104         return locals()
00105     sftp = property(**sftp())
00106     
00107     def hostname():
00108         doc = "hostname"
00109         def fget(self):
00110             return self.__hostname__
00111         def fset(self, hostname):
00112             self.__hostname__ = hostname
00113         return locals()
00114     hostname = property(**hostname())
00115     
00116     def port():
00117         doc = "port"
00118         def fget(self):
00119             return self.__port__
00120         def fset(self, port):
00121             self.__port__ = port
00122         return locals()
00123     port = property(**port())
00124 
00125     def username():
00126         doc = "username"
00127         def fget(self):
00128             return self.__username__
00129         def fset(self, username):
00130             self.__username__ = username
00131         return locals()
00132     username = property(**username())
00133 
00134     def password():
00135         doc = "password"
00136         def fget(self):
00137             return self.__password__
00138         def fset(self, password):
00139             self.__password__ = password
00140         return locals()
00141     password = property(**password())
00142 
00143     def lastError():
00144         doc = "lastError message - use getvalue() to retrieve the message"
00145         def fget(self):
00146             return self.__lastError__
00147         return locals()
00148     lastError = property(**lastError())
00149 
00150     def lastErrorMessage():
00151         doc = "lastError message"
00152         def fget(self):
00153             return self.__lastError__.getvalue()
00154         return locals()
00155     lastErrorMessage = property(**lastErrorMessage())
00156 
00157     ##
00158     #  Make an SSH connection with the server to mimic certain functions only for win32 platform to facilitate development.
00159     #   
00160     def ssh_connect_transport(self):
00161         # get host key, if we know one
00162         hostkeytype = None
00163         hostkey = None
00164         try:
00165             host_keys = paramiko.util.load_host_keys(os.path.expanduser('~/.ssh/known_hosts'))
00166         except IOError:
00167             try:
00168                 host_keys = paramiko.util.load_host_keys(os.path.expanduser('~/ssh/known_hosts'))
00169             except IOError:
00170                 exc_info = sys.exc_info()
00171                 info_string = '\n'.join(traceback.format_exception(*exc_info))
00172                 print >>self.lastError, '\n%s :: Cannot open host keys file, Reason: %s' % (ObjectTypeName.objectSignature(self),info_string)
00173                 host_keys = {}
00174         if host_keys.has_key(self.hostname):
00175             hostkeytype = host_keys[self.hostname].keys()[0]
00176             hostkey = host_keys[self.hostname][hostkeytype]
00177         else:
00178             print "%s :: Host key not found. Please create key manually using: ssh %s" % (misc.funcName(),self.hostname)
00179         # now, connect and use paramiko Transport to negotiate SSH2 across the connection
00180         try:
00181             t = paramiko.Transport((self.hostname, self.port))
00182             t.connect(username=self.username, password=self.password, hostkey=hostkey)
00183         except Exception, e:
00184             exc_info = sys.exc_info()
00185             info_string = '\n'.join(traceback.format_exception(*exc_info))
00186             print >>self.lastError, '\n%s :: Cannot open connection to %s:%s using username of "%s", Reason: %s' % (ObjectTypeName.objectSignature(self),self.hostname,self.port,self.username,info_string)
00187             return None
00188         return t
00189 
00190     ##
00191     #  connect and use paramiko Transport to negotiate SSH2 across the connection
00192     #   
00193     def ssh_connect_client(self):
00194         self.__sftp__ = None
00195         if (self.transport is None):
00196             self.__transport__ = self.ssh_connect_transport()
00197         if (self.__transport__ is not None):
00198             try:
00199                 self.__sftp__ = paramiko.SFTPClient.from_transport(self.transport)
00200             except Exception, e:
00201                 exc_info = sys.exc_info()
00202                 info_string = '\n'.join(traceback.format_exception(*exc_info))
00203                 print >>self.lastError, '\n%s :: Cannot open client connection to %s:%s using username of "%s", Reason: %s' % (ObjectTypeName.objectSignature(self),self.hostname,self.port,self.username,info_string)
00204                 try:
00205                     if (self.sftp is not None):
00206                         ssh_close()
00207                 except:
00208                     pass
00209                 return None
00210         else:
00211             return None
00212     
00213         return self.sftp
00214 
00215     ##
00216     # Close the previously opened client connection as obtained by ssh_connect_client()
00217     def ssh_close(self):
00218         try:
00219             self.sftp.close()
00220             self.__sftp__ = None
00221         except:
00222             pass
00223         try:
00224             self.transport.close()
00225             self.__transport__ = None
00226         except:
00227             pass
00228         return
00229 
00230     ##
00231     #  Perform directoy list against an SSH accessible server.
00232     #   
00233     def __ssh_listdir(self,dir_path):
00234         if ((dir_path == None) or (dir_path == '')): 
00235             dir_path = '.'
00236         try:
00237             dirlist = self.sftp.listdir(dir_path)
00238         except:
00239             return None
00240         return dirlist
00241 
00242     ##
00243     # 
00244     #   Return a list containing the names of the entries in the given path. The list is in arbitrary order. It does not include the special entries '.' and '..' even if they are present in the folder. This method is meant to mirror os.listdir as closely as possible. For a list of full SFTPAttributes  objects, see listdir_attr.
00245     #   
00246     #   Parameters:
00247     #       * path (str) - path to list (defaults to '.')
00248     #   
00249     #   Returns: list of str
00250     #       list of filenames   
00251     #   
00252     def listdir(self,pathName):
00253         return self.__ssh_listdir(pathName)
00254 
00255     ##
00256     # 
00257     #   Return the normalized path (on the server) of a given path. This can be used to quickly resolve symbolic links or determine what the server is considering to be the "current folder" (by passing '.' as path).
00258     #   
00259     #   Parameters:
00260     #       * path (str) - path to be normalized
00261     #   
00262     #   Returns: str
00263     #       normalized form of the given path
00264     #       
00265     #   Raises:
00266     #       * IOError - if the path can't be resolved on the server
00267     #   
00268     def normalize(self,dir_path):
00269         if ((dir_path == None) or (dir_path == '')): 
00270             dir_path = '.'
00271         try:
00272             return self.sftp.normalize(dir_path)
00273         except:
00274             return None
00275         return None
00276 
00277     ##
00278     # 
00279     #   Change the "current directory" of this SFTP session. Since SFTP doesn't really have the concept of a current working directory, this is emulated by paramiko. Once you use this method to set a working directory, all operations on this SFTPClient object will be relative to that path.
00280     #   
00281     #   Parameters:
00282     #       * path (str) - new current working directory
00283     #   
00284     #   Raises:
00285     #       * IOError - if the requested path doesn't exist on the server
00286     #   
00287     def chdir(self,dir_path):
00288         try:
00289             return self.sftp.chdir(dir_path)
00290         except:
00291             return None
00292         return None
00293 
00294     ##
00295     # 
00296     #   Change the mode (permissions) of a file. The permissions are unix-style and identical to those used by python's os.chmod function.
00297     #   
00298     #   Parameters:
00299     #       * path (str) - path of the file to change the permissions of
00300     #       * mode (int) - new permissions
00301     #   
00302     def chmod(self,path,mode):
00303         try:
00304             return self.sftp.chmod(path,mode)
00305         except:
00306             return None
00307         return None
00308 
00309     ##
00310     # 
00311     #   Change the owner (uid) and group (gid) of a file. As with python's os.chown function, you must pass both arguments, so if you only want to change one, use stat first to retrieve the current owner and group.
00312     #   
00313     #   Parameters:
00314     #       * path (str) - path of the file to change the owner and group of
00315     #       * uid (int) - new owner's uid
00316     #       * gid (int) - new group id
00317     #   
00318     def chown(self,path,uid,gid):
00319         try:
00320             return self.sftp.chown(path,uid,gid)
00321         except:
00322             return None
00323         return None
00324 
00325     ##
00326     # 
00327     #   Close the SFTP session and its underlying channel.
00328     #   
00329     def close(self):
00330         return self.ssh_close()
00331 
00332     ##
00333     # 
00334     #   Return the underlying Channel object for this SFTP session. This might be useful for doing things like setting a timeout on the channel.
00335     #   
00336     #   Returns: Channel
00337     #       the SSH channel 
00338     #   
00339     def get_channel(self):
00340         try:
00341             return self.sftp.get_channel()
00342         except:
00343             return None
00344         return None
00345 
00346     ##
00347     # 
00348     #   Return the "current working directory" for this SFTP session, as emulated by paramiko. If no directory has been set with chdir, this method will return None.
00349     #   
00350     #   Returns: str
00351     #       the current working directory on the server, or None        
00352     #   
00353     def getcwd(self):
00354         try:
00355             f = self.sftp.getcwd()
00356             return f if (f is not None) else self.home()
00357         except:
00358             return None
00359         return None
00360 
00361     ##
00362     # 
00363     #   Return a list containing SFTPAttributes objects corresponding to files in the given path. The list is in arbitrary order. It does not include the special entries '.' and '..' even if they are present in the folder.
00364     #   
00365     #   The returned SFTPAttributes objects will each have an additional field: longname, which may contain a formatted string of the file's attributes, in unix format. The content of this string will probably depend on the SFTP server implementation.
00366     #   
00367     #   Parameters:
00368     #       * path (str) - path to list (defaults to '.')
00369     #   
00370     #   Returns: list of SFTPAttributes
00371     #       list of attributes  
00372     #   
00373     def listdir_attr(self,dir_path):
00374         try:
00375             return self.sftp.listdir_attr(dir_path)
00376         except:
00377             return None
00378         return None
00379 
00380     ##
00381     # 
00382     #   Retrieve information about a file on the remote system. The return value is an object whose attributes correspond to the attributes of python's stat structure as returned by os.stat, except that it contains fewer fields. An SFTP server may return as much or as little info as it wants, so the results may vary from server to server.
00383     #   
00384     #   Unlike a python stat object, the result may not be accessed as a tuple. This is mostly due to the author's slack factor.
00385     #   
00386     #   The fields supported are: st_mode, st_size, st_uid, st_gid, st_atime, and st_mtime.
00387     #   
00388     #   Parameters:
00389     #   
00390     #       * path (str) - the filename to stat
00391     #   
00392     #   Returns: SFTPAttributes
00393     #       an object containing attributes about the given file        
00394     #   
00395     def stat(self,dir_path):
00396         try:
00397             return self.sftp.stat(dir_path)
00398         except:
00399             return None
00400         return None
00401     
00402     ##
00403     # 
00404     #   Retrieve information about a file on the remote system, without following symbolic links (shortcuts). This otherwise behaves exactly the same as stat.
00405     #   
00406     #   Parameters:
00407     #       * path (str) - the filename to stat
00408     #   
00409     #   Returns: SFTPAttributes
00410     #       an object containing attributes about the given file        
00411     #   
00412     def lstat(self,dir_path):
00413         try:
00414             return self.sftp.lstat(dir_path)
00415         except:
00416             return None
00417         return None
00418     
00419     ##
00420     # 
00421     #   Create a folder (directory) named path with numeric mode mode. The default mode is 0777 (octal). On some systems, mode is ignored. Where it is used, the current umask value is first masked out.
00422     #   
00423     #   Parameters:
00424     #       * path (str) - name of the folder to create
00425     #       * mode (int) - permissions (posix-style) for the newly-created folder
00426     #   
00427     def mkdir(self,dir_path,file_mode=0777):
00428         try:
00429             return self.sftp.mkdir(dir_path,file_mode)
00430         except:
00431             return None
00432         return None
00433     
00434     ##
00435     # 
00436     #   Open a file on the remote server. The arguments are the same as for python's built-in file (aka open). A file-like object is returned, which closely mimics the behavior of a normal python file object.
00437     #   
00438     #   The mode indicates how the file is to be opened: 'r' for reading, 'w' for writing (truncating an existing file), 'a' for appending, 'r+' for reading/writing, 'w+' for reading/writing (truncating an existing file), 'a+' for reading/appending. The python 'b' flag is ignored, since SSH treats all files as binary. The 'U' flag is supported in a compatible way.
00439     #   
00440     #   Since 1.5.2, an 'x' flag indicates that the operation should only succeed if the file was created and did not previously exist. This has no direct mapping to python's file flags, but is commonly known as the O_EXCL flag in posix.
00441     #   
00442     #   The file will be buffered in standard python style by default, but can be altered with the bufsize parameter. 0 turns off buffering, 1 uses line buffering, and any number greater than 1 (>1) uses that specific buffer size.
00443     #   
00444     #   Parameters:
00445     #       * filename (str) - name of the file to open
00446     #       * mode (str) - mode (python-style) to open in
00447     #       * bufsize (int) - desired buffering (-1 = default buffer size)
00448     #   
00449     #   Returns: SFTPFile
00450     #       a file object representing the open file
00451     #       
00452     #   Raises:
00453     #       * IOError - if the file could not be opened.
00454     #   
00455     def file(self,filename,mode='r',bufsize=-1):
00456         try:
00457             return self.sftp.file(filename,mode,bufsize)
00458         except:
00459             return None
00460         return None
00461     
00462     ##
00463     # 
00464     #   Open a file on the remote server. The arguments are the same as for python's built-in file (aka open). A file-like object is returned, which closely mimics the behavior of a normal python file object.
00465     #   
00466     #   The mode indicates how the file is to be opened: 'r' for reading, 'w' for writing (truncating an existing file), 'a' for appending, 'r+' for reading/writing, 'w+' for reading/writing (truncating an existing file), 'a+' for reading/appending. The python 'b' flag is ignored, since SSH treats all files as binary. The 'U' flag is supported in a compatible way.
00467     #   
00468     #   Since 1.5.2, an 'x' flag indicates that the operation should only succeed if the file was created and did not previously exist. This has no direct mapping to python's file flags, but is commonly known as the O_EXCL flag in posix.
00469     #   
00470     #   The file will be buffered in standard python style by default, but can be altered with the bufsize parameter. 0 turns off buffering, 1 uses line buffering, and any number greater than 1 (>1) uses that specific buffer size.
00471     #   
00472     #   Parameters:
00473     #       * filename (str) - name of the file to open
00474     #       * mode (str) - mode (python-style) to open in
00475     #       * bufsize (int) - desired buffering (-1 = default buffer size)
00476     #   
00477     #   Returns: SFTPFile
00478     #       a file object representing the open file
00479     #       
00480     #   Raises:
00481     #       * IOError - if the file could not be opened.
00482     #   
00483     def open(self,filename,mode='r',bufsize=-1):
00484         try:
00485             return self.sftp.open(filename,mode,bufsize)
00486         except:
00487             return None
00488         return None
00489     
00490     ##
00491     # 
00492     #   Copy a remote file (remotepath) from the SFTP server to the local host as localpath. Any exception raised by operations will be passed through. This method is primarily provided as a convenience.
00493     #   
00494     #   Parameters:
00495     #       * remotepath (str) - the remote file to copy
00496     #       * localpath (str) - the destination path on the local host
00497     #       * callback (function(int, int)) - optional callback function that accepts the bytes transferred so far and the total bytes to be transferred (since 1.7.4)
00498     #   
00499     def get(self,remotepath,localpath,callback=None):
00500         try:
00501             return self.sftp.get(remotepath,localpath,callback=None)
00502         except:
00503             return None
00504         return None
00505     
00506     ##
00507     # 
00508     #   Copy a local file (localpath) to the SFTP server as remotepath. Any exception raised by operations will be passed through. This method is primarily provided as a convenience.
00509     #   
00510     #   The SFTP operations use pipelining for speed.
00511     #   
00512     #   Parameters:
00513     #       * localpath (str) - the local file to copy
00514     #       * remotepath (str) - the destination path on the SFTP server
00515     #       * callback (function(int iBytes, int iTotal, float xfer_rate, int elapsed_secs)) - optional callback function that accepts the bytes transferred so far and the total bytes to be transferred (since 1.7.4)
00516     #   
00517     #   Returns: SFTPAttributes
00518     #       an object containing attributes about the given file (since 1.7.4)  
00519     #   
00520     def put(self,localpath,remotepath,callback=None):
00521         import time
00522         from vyperlogix.misc import _utils
00523         
00524         _begin_ts = time.time()
00525         _callback_ = None
00526         def _callback(iBytes,iTotal):
00527             if (callable(_callback_)):
00528                 et = time.time() - _begin_ts
00529                 if (et == 0):
00530                     et = 0.00000000001
00531                 xfer = iBytes / et
00532                 try:
00533                     _callback_(iBytes,iTotal,xfer,et)
00534                 except Exception, details:
00535                     print >>sys.stderr, '%s' % str(details)
00536         
00537         try:
00538             if (not callable(callback)):
00539                 callback = None
00540             else:
00541                 try:
00542                     callback(0,0,0,0)
00543                 except Exception, details:
00544                     print >>sys.stderr, '%s :: Cannot use the callback because it has the following problem: "%s".' % (ObjectTypeName.objectSignature(self),str(details))
00545                     callback = None
00546             if (callback is not None):
00547                 _callback_ = callback
00548             result = self.sftp.put(localpath,remotepath,_callback)
00549             _end_ts = time.time()
00550             _iTotal = result.st_size
00551             xfer = _iTotal / (_end_ts - _begin_ts)
00552             return [result,xfer]
00553         except:
00554             exc_info = sys.exc_info()
00555             info_string = _utils.asMessage('\n'.join(traceback.format_exception(*exc_info)))
00556             print >>sys.stderr, info_string
00557             return None
00558         return None
00559     
00560     ##
00561     # 
00562     #   Return the target of a symbolic link (shortcut). You can use symlink to create these. The result may be either an absolute or relative pathname.
00563     #   
00564     #   Parameters:
00565     #       * path (str) - path of the symbolic link file
00566     #   
00567     #   Returns: str
00568     #       target path         
00569     #   
00570     def readlink(self,dir_path):
00571         try:
00572             return self.sftp.readlink(dir_path)
00573         except:
00574             return None
00575         return None
00576     
00577     ##
00578     # 
00579     #   Remove the file at the given path. This only works on files; for removing folders (directories), use rmdir.
00580     #   
00581     #   Parameters:
00582     #       * path (str) - path (absolute or relative) of the file to remove
00583     #   
00584     #   Raises:
00585     #       * IOError - if the path refers to a folder (directory)
00586     #   
00587     def remove(self,dir_path):
00588         try:
00589             return self.sftp.remove(dir_path)
00590         except:
00591             return None
00592         return None
00593     
00594     ##
00595     # 
00596     #   Rename a file or folder from oldpath to newpath.
00597     #   
00598     #   Parameters:
00599     #       * oldpath (str) - existing name of the file or folder
00600     #       * newpath (str) - new name for the file or folder
00601     #   
00602     #   Raises:
00603     #       * IOError - if newpath is a folder, or something else goes wrong
00604     #   
00605     def rename(self,old_name,new_name):
00606         try:
00607             return self.sftp.rename(old_name,new_name)
00608         except:
00609             return None
00610         return None
00611     
00612     ##
00613     # 
00614     #   Remove the folder named path.
00615     #   
00616     #   Parameters:
00617     #       * path (str) - name of the folder to remove
00618     #   
00619     def rmdir(self,fname):
00620         try:
00621             return self.sftp.rmdir(fname)
00622         except:
00623             return None
00624         return None
00625     
00626     ##
00627     # 
00628     #   Create a symbolic link (shortcut) of the source path at destination.
00629     #   
00630     #   Parameters:
00631     #       * source (str) - path of the original file
00632     #       * dest (str) - path of the newly created symlink
00633     #   
00634     def symlink(self,source,dest):
00635         try:
00636             return self.sftp.symlink(source,dest)
00637         except:
00638             return None
00639         return None
00640     
00641     ##
00642     # 
00643     #   Change the size of the file specified by path. This usually extends or shrinks the size of the file, just like the truncate() method on python file objects.
00644     #   
00645     #   Parameters:
00646     #       * path (str) - path of the file to modify
00647     #       * size (int or long) - the new size of the file
00648     #   
00649     def truncate(self,fname,fsize):
00650         try:
00651             return self.sftp.truncate(fname,fsize)
00652         except:
00653             return None
00654         return None
00655     
00656     ##
00657     # 
00658     #   Remove the file at the given path. This only works on files; for removing folders (directories), use rmdir.
00659     #   
00660     #   Parameters:
00661     #       * path (str) - path (absolute or relative) of the file to remove
00662     #   
00663     #   Raises:
00664     #       * IOError - if the path refers to a folder (directory)
00665     #   
00666     def unlink(self,fname):
00667         try:
00668             return self.sftp.unlink(fname)
00669         except:
00670             return None
00671         return None
00672     
00673     ##
00674     #  
00675     #   Set the access and modified times of the file specified by path. If times is None, then the file's access and modified times are set to the current time. Otherwise, times must be a 2-tuple of numbers, of the form (atime, mtime), which is used to set the access and modified times, respectively. This bizarre API is mimicked from python for the sake of consistency -- I apologize.
00676     # 
00677     #   Parameters:
00678     #       * path (str) - path of the file to modify
00679     #       * times (tuple(int)) - None or a tuple of (access time, modified time) in standard internet epoch time (seconds since 01 January 1970 GMT)
00680     #   
00681     def utime(self,fname,times):
00682         try:
00683             return self.sftp.utime(fname,times)
00684         except:
00685             return None
00686         return None
00687 
00688     ##
00689     #  home folder for current user 
00690     def home(self):
00691         f = self.normalize(self.getcwd())
00692         toks = f.split(self.sep)
00693         t = toks[0:3]
00694         return self.sep.join(t)
00695 
00696     ##
00697     # Test whether a remote path is a directory
00698     def isdir(self, pathName):
00699         import stat
00700         try:
00701             st = self.stat(pathName)
00702             return False if (st == None) else stat.S_ISDIR(st.st_mode)
00703         except os.error:
00704             return False
00705         return False
00706 
00707     ##
00708     # Test whether a path is a symbolic link
00709     def islink(self, pathName):
00710         import stat
00711         try:
00712             st = self.lstat(pathName)
00713         except (os.error, AttributeError):
00714             return False
00715         return stat.S_ISLNK(st.st_mode)
00716 
00717     ##
00718     # Remote Directory tree generator.
00719     #     
00720     #         For each directory in the remote directory tree rooted at top (including top
00721     #         itself, but excluding '.' and '..'), yields a 3-tuple
00722     #     
00723     #             dirpath, dirnames, filenames
00724     #     
00725     #         dirpath is a string, the path to the directory.  dirnames is a list of
00726     #         the names of the subdirectories in dirpath (excluding '.' and '..').
00727     #         filenames is a list of the names of the non-directory files in dirpath.
00728     #         Note that the names in the lists are just names, with no path components.
00729     #         To get a full path (which begins with top) to a file or directory in
00730     #         dirpath, do os.path.join(dirpath, name).
00731     #     
00732     #         If optional arg 'topdown' is true or not specified, the triple for a
00733     #         directory is generated before the triples for any of its subdirectories
00734     #         (directories are generated top down).  If topdown is false, the triple
00735     #         for a directory is generated after the triples for all of its
00736     #         subdirectories (directories are generated bottom up).
00737     #     
00738     #         When topdown is true, the caller can modify the dirnames list in-place
00739     #         (e.g., via del or slice assignment), and walk will only recurse into the
00740     #         subdirectories whose names remain in dirnames; this can be used to prune
00741     #         the search, or to impose a specific order of visiting.  Modifying
00742     #         dirnames when topdown is false is ineffective, since the directories in
00743     #         dirnames have already been generated by the time dirnames itself is
00744     #         generated.
00745     #     
00746     #         By default errors from the os.listdir() call are ignored.  If
00747     #         optional arg 'onerror' is specified, it should be a function; it
00748     #         will be called with one argument, an os.error instance.  It can
00749     #         report the error to continue with the walk, or raise the exception
00750     #         to abort the walk.  Note that the filename is available as the
00751     #         filename attribute of the exception object.
00752     #     
00753     #         Caution:  if you pass a relative pathname for top, don't change the
00754     #         current working directory between resumptions of walk.  walk never
00755     #         changes the current directory, and assumes that the client doesn't
00756     #         either.
00757     #     
00758     #         Example:
00759     #     
00760     #         from os.path import join, getsize
00761     #         for root, dirs, files in walk('python/Lib/email'):
00762     #             print root, "consumes",
00763     #             print sum([getsize(join(root, name)) for name in files]),
00764     #             print "bytes in", len(files), "non-directory files"
00765     #             if 'CVS' in dirs:
00766     #                 dirs.remove('CVS')  # don't visit CVS directories
00767     #         
00768     def walk(self, top, topdown=True, onerror=None):
00769     
00770         from posixpath import join
00771     
00772         # We may not have read permission for top, in which case we can't
00773         # get a list of the files the directory contains.  os.path.walk
00774         # always suppressed the exception then, rather than blow up for a
00775         # minor reason when (say) a thousand readable directories are still
00776         # left to visit.  That logic is copied here.
00777         try:
00778             # Note that listdir and error are globals in this module due
00779             # to earlier import-*.
00780             names = self.listdir(top)
00781         except error, err:
00782             if (callable(onerror)):
00783                 try:
00784                     onerror(err)
00785                 except:
00786                     pass
00787             return
00788     
00789         dirs, nondirs = [], []
00790         if (names is not None):
00791             for name in names:
00792                 if self.isdir(join(top, name)):
00793                     dirs.append(name)
00794                 else:
00795                     nondirs.append(name)
00796         
00797             if topdown:
00798                 yield top, dirs, nondirs
00799             for name in dirs:
00800                 path = join(top, name)
00801                 if not self.islink(path):
00802                     for x in self.walk(path, topdown, onerror):
00803                         yield x
00804             if not topdown:
00805                 yield top, dirs, nondirs
00806         else:
00807             print '(%s) :: Possibly no files found at "%s".' % (ObjectTypeName.objectSignature(self),top)
00808     
00809     ##
00810     #  Search for a folder of a specific name 
00811     def searchForFolderNamed(self,fname,top='/'):
00812         for root, dirs, files in self.walk(top, topdown=True):
00813             if (fname in dirs):
00814                 return self.sep.join([root,fname])
00815         return ''
00816 
00817     ##
00818     #  Perform os.path.exists().
00819     #         
00820     def exists(self,pathName):
00821         return self.stat(pathName) != None
00822     
00823     ##
00824     # Chmod the tree at path (Chmod recursively on a whole subtree)
00825     def chmod_tree(self, path, mode, mask):
00826         import stat
00827         def visit(arg, dirname, names):
00828             mode, mask = arg
00829             for name in names:
00830                 fullname = self.sep.join([dirname, name])
00831                 if not self.islink(fullname):
00832                     new_mode = (self.stat(fullname)[stat.ST_MODE] & ~mask) | mode
00833                     self.chmod(fullname, new_mode)
00834         self.walk(path, visit, (mode, mask))
00835     
00836     def fileSize(self,fname):
00837         if (self.exists(fname)):
00838             st = self.stat(fname)
00839             return st.st_size
00840         return -1
00841 
00842     ##
00843     # Recursively delete a directory tree.
00844     #     
00845     #   If ignore_errors is set, errors are ignored; otherwise, if onerror
00846     #   is set, it is called to handle the error with arguments (func,
00847     #   path, exc_info) where func is os.listdir, os.remove, or os.rmdir;
00848     #   path is the argument to that function that caused it to fail; and
00849     #   exc_info is a tuple returned by sys.exc_info().  If ignore_errors
00850     #   is false and onerror is None, an exception is raised.
00851     #     
00852     #   
00853     def rmtree(self, path, ignore_errors=False, onerror=None):
00854         import sys, stat
00855         if ignore_errors:
00856             def onerror(*args):
00857                 pass
00858         elif onerror is None:
00859             def onerror(*args):
00860                 raise
00861         names = []
00862         try:
00863             names = self.listdir(path)
00864         except os.error, err:
00865             onerror(self.listdir, path, sys.exc_info())
00866         for name in names:
00867             fullname = self.sep.join([path, name])
00868             try:
00869                 mode = self.lstat(fullname).st_mode
00870             except os.error:
00871                 mode = 0
00872             if stat.S_ISDIR(mode):
00873                 self.rmtree(fullname, ignore_errors, onerror)
00874             else:
00875                 try:
00876                     self.remove(fullname)
00877                 except os.error, err:
00878                     onerror(self.remove, fullname, sys.exc_info())
00879         try:
00880             self.rmdir(path)
00881         except os.error:
00882             onerror(self.rmdir, path, sys.exc_info())
00883             
00884     ##
00885     # Remove the tree at DIRNAME (For clearing away read-only directories)
00886     def safe_rmtree(dirname, retry=0):
00887         import os, sys, time
00888         def rmtree(dirname):
00889             self.chmod_tree(dirname, 0666, 0666)
00890             self.rmtree(dirname)
00891     
00892         if not self.exists(dirname):
00893             return
00894     
00895         if retry:
00896             for delay in (0.5, 1, 2, 4):
00897                 try:
00898                     self.rmtree(dirname)
00899                     break
00900                 except:
00901                     time.sleep(delay)
00902             else:
00903                 self.rmtree(dirname)
00904         else:
00905             self.rmtree(dirname)
00906 
00907 def sftp_to_host(hostname,username,password,source,dest,isSilent=False):
00908     try:
00909         ssh = SSHConnection(hostname=hostname,username=username,password=password)
00910     except:
00911         exc_info = sys.exc_info()
00912         info_string = _utils.asMessage('\n'.join(traceback.format_exception(*exc_info)))
00913         print >>sys.stderr, info_string
00914     if (not isSilent):
00915         print 'ssh.transport = %s' % (ssh.transport)
00916     if (ssh.transport):
00917         results = [0,-1]
00918         try:
00919             if (not isSilent):
00920                 print 'ssh.isdir(%s)=%s' % (dest,ssh.isdir(dest))
00921             if (ssh.isdir(dest)):
00922                 dest = ssh.sep.join([dest,os.path.basename(source)])
00923             if (not isSilent):
00924                 print 'dest=%s' % (dest)
00925                 print 'ssh.exists(%s)=%s' % (dest,ssh.exists(dest))
00926             if (ssh.exists(dest)):
00927                 if (not isSilent):
00928                     print 'ssh.remove(%s)' % (dest)
00929                 ssh.remove(dest)
00930             if (not isSilent):
00931                 print 'SFTP "%s" to host as "%s".' % (source,dest)
00932             results = ssh.put(source, dest, callback=giveXferStatus if (not isSilent) else None)
00933         except:
00934             exc_info = sys.exc_info()
00935             info_string = _utils.asMessage('\n'.join(traceback.format_exception(*exc_info)))
00936             print >>sys.stderr, info_string
00937         finally:
00938             xfer_rate_calc = lists.HashedLists2() if (results is None) else calcXferRate(results[-1])
00939             if (not isSilent):
00940                 print 'SFTP Done, %s, Closing Connection.' % (xfer_rate_calc['xfer_rate_fmt'])
00941             ssh.close()
00942     else:
00943         print >>sys.stderr, 'Unable to get a connection with the server using "%s".' % ('%s,%s,%s' % (hostname,username,password))
00944 
00945 if __name__ == "__main__":
00946     import sys
00947     print >>sys.stdout, __copyright__
00948     print >>sys.stderr, __copyright__
00949 
00950 

© Copyright 2008-2009 Vyper Logix Corp., All Right Reserved; If you reference this document or any part of this document you must use the citation verbatim (including the link) "© Copyright 2008-2009 Vyper Logix Corp., All Right Reserved."

Notice: This source code contained in this document is NOT open source and is NOT being distributed as open source.

122,241 lines of code and growing...