#!/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 #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): #looks for whether the link originates 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 list 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 = open(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") def displayFiles(ftp): data = {} data = DirScanner() #create data object of class DirScanner ftp.dir(data.addline) #add lines to dict when dir is run keys = data.keys() #get the keys keys.sort() #sort it #print it to the sorted filenames for i,eachEntry in enumerate(keys): if data[eachEntry].getType() == '-': #DirEntry object using fileName key print '(',i,'):\t[FILE]\t',eachEntry elif data[eachEntry].getType() == 'd': #same as above but directory print '(',i,'):\t [DIR]\t',eachEntry print '\n[u]: go up one directory' print '[e]: exit\n' return data #main start here ftp = ftplib.FTP('ftp.perforce.com','ftp','ident') data = displayFiles(ftp) choice = raw_input("Choose the directory 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 downloadFile(ftp,fileName) elif data[fileName].getType() == 'd': #same as above but directory ftp.cwd(fileName) else: print "\n*** You have made an invalid choice ***\n" data = displayFiles(ftp) choice = raw_input("choose the directory from the above choices: ") ftp.quit()