#!/usr/bin/python #Author: Stephen Moon #Date: 3/5/09 #Retrieves Perforce binaries or ASCII files from ftp.perforce.com # #Usage: # # In Windows, remove she-bang line # import ftplib, re, os, sys HOST = 'ftp.perforce.com' DIR_NAME = 'perforce' #holds each displayed line entry class DirEntry(object): #inherits from class object def __init__(self,line): #only accept one argument line self.parts = line.split(None,8) #split into 8 parts for each line def isValid(self): return len(self.parts) >= 6 #if num of parts greater than 6 then it's valid def getType(self): return self.parts[0][0] #get the very first character on the line (i.e. def getFilename(self): if self.getType() != 'l': #if it is not a link return self.parts[-1] #return the last part else: return self.parts[-1].split(' -> ', 1)[0] #if it is, return shortcut def getLinkDest(self): #return the original destination of link if self.getType() == 'l': return self.parts[-1].split(' -> ', 1)[1] else: raise RuntimeError, "getLinkDest() called on non-link item" #creates a key (fname) and value (line for the filename) class DirScanner(dict): #inherits from class dict def addline(self,line): #only accepts one arugment line obj = DirEntry(line) if obj.isValid(): #line object contains more than 6 parts self[obj.getFilename()] = obj #creates a key/value pair, key = fname #downloads a file def downloadFile(ftpobj, filename): ftpobj.voidcmd("Type I") #based on the filename, it returns a tuple of the data connection and the expected #size of data datasock, estimatedSize = ftpobj.ntransfercmd("RETR %s" % filename) transbytes = 0 fd = file(filename, 'wb') while True: buf = datasock.recv(2048) if not len(buf): break; fd.write(buf) transbytes += len(buf) sys.stdout.write("%s: Received %d " % (filename, transbytes)) if estimatedSize: sys.stdout.write("of %d bytes (%.1f%%)\n" % (estimatedSize, 100.0 * float(transbytes) / float(estimatedSize))) else: sys.stdout.write("bytes") fd.close() datasock.close() ftpobj.voidresp() sys.stdout.write("\n") #displays the entries for a chosen directory def displayFiles(ftp): data = {} data = DirScanner() #create data object of class DirScanner ftp.dir(data.addline) #add lines to dict when dir is run f = '[FILE]' d = '[DIR]' keys = data.keys() #get the keys keys.sort() #sort it #print it to the sorted filenames print "\nCurrent Working Directory: ",ftp.pwd(),"\n" for i,eachEntry in enumerate(keys): if data[eachEntry].getType() == '-': #DirEntry object using fileName key print '%2s:%6s %s' % (str(i),f,eachEntry) elif data[eachEntry].getType() == 'd': #same as above but directory print '%2s:%6s %s' % (str(i),d,eachEntry) #print '('+str(i)+'):\t [DIR] ',eachEntry print '\n%2s: go up one directory' % 'u' print '%2s: exit\n' % 'e' return data #main starts here def main(): try: ftp = ftplib.FTP(HOST) except (socket.error, socket.gaierror), e: print 'Error: cannot reach "%s"' % HOST return print '\n*** Connected to host "%s" ***' % HOST try: ftp.login() except ftplib.error_perm: print 'Error: cannot login anonymously' return try: ftp.cwd(DIR_NAME) except ftplib.error_perm: print 'Error: cannot change directory to "%s"' % DIR_NAME ftp.quit() return data = displayFiles(ftp) choice = raw_input("Choose a directory or file from the above choices: ") while True: if choice is 'u': ftp.cwd("..") elif choice is 'e': break; elif choice.isalpha(): print "\n*** You have entered alpha character other than given choices ***\n" elif(int(choice) <= len(data) - 1): keys = data.keys() keys.sort() # filenames sorted for i, fileName in enumerate(keys): if i == int(choice): if data[fileName].getType() == '-': #DirEntry object using fileName key try: downloadFile(ftp,fileName) except ftplib.error_perm: print 'Error: cannot download file "%s"' % fileName os.unlink(fileName) else: print '*** Downloaded "%s" to current local directory ***' % fileName elif data[fileName].getType() == 'd': #same as above but directory try: ftp.cwd(fileName) except ftplib.error_perm: print 'Error: cannot cd to "%s"' % fileName return else: print "\n*** You have made an invalid choice ***\n" data = displayFiles(ftp) choice = raw_input("Choose a directory or file from the above choices: ") ftplib.FTP(HOST).quit() if __name__ == '__main__': main()
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#24 | 8645 | Stephen Moon | removing not up-to-date scripts | ||
#23 | 7574 | Stephen Moon |
Ignore previous revision. The change was inadvertently submitted. The change to correct the previous submission mistake |
||
#22 | 7573 | Stephen Moon | optparse added to accept a filename from the command line and print usage info | ||
#21 | 7538 | Stephen Moon | now accept login and password | ||
#20 | 7324 | Stephen Moon | modified download progress message logic | ||
#19 | 7323 | Stephen Moon | added disclaimer | ||
#18 | 7322 | Stephen Moon | implementation of download progress using set | ||
#17 | 7320 | Stephen Moon | changed the code so the download update is less verbose | ||
#16 | 7168 | Stephen Moon | comment added and she-bang line modified | ||
#15 | 7167 | Stephen Moon | Re-added error check | ||
#14 | 7166 | Stephen Moon | created initialize() by refactoring main() | ||
#13 | 7165 | Stephen Moon | Added date | ||
#12 | 7164 | Stephen Moon | Now shows file size | ||
#11 | 7162 | Stephen Moon | bug fix and some formattig changes | ||
#10 | 7161 | Stephen Moon |
alphanumeric input error fixed for sure... please test |
||
#9 | 7160 | Stephen Moon | alphanumeric character bug fixed | ||
#8 | 7159 | Stephen Moon | a bit more formatting change | ||
#7 | 7158 | Stephen Moon | log into perforce dir and shows current working dir | ||
#6 | 7157 | Stephen Moon | made some bug fixes | ||
#5 | 7156 | Stephen Moon | added error checks | ||
#4 | 7155 | Stephen Moon | some more formatting changes | ||
#3 | 7154 | Stephen Moon | minor formatting changes | ||
#2 | 7153 | Stephen Moon | Now shows [DIR] and [FILE] in front of each entry | ||
#1 | 7152 | Stephen Moon | program to retrieve files from ftp.perforce.com |