Annotation of cdli/tools/uploadATF.py, revision 1.2

1.1       dwinter     1: import sys
                      2: from ZODB import DB
                      3: from ZEO import ClientStorage
                      4: from ZPublisher.HTTPResponse import HTTPResponse
                      5: from ZPublisher.HTTPRequest import HTTPRequest
                      6: from ZPublisher.BaseRequest import RequestContainer
                      7: 
                      8: import logging
                      9: import os
                     10: import os.path
                     11: import tempfile
                     12: import codecs
                     13: from Products.cdli.cdli_files import CDLIRoot
                     14: 
                     15: import pickle
                     16: 
                     17: class StoreObject:
1.2     ! dwinter    18:     
        !            19:     
1.1       dwinter    20:     returnValue={}
                     21:     def __init__(self,storeId):
                     22:         self.storeId= storeId
                     23:     
                     24:     
                     25:     def save(self):
                     26:         pf = file("/tmp/"+self.storeId+".result","w")
                     27:         pickle.dump(self.returnValue,pf)
                     28:         pf.close()
                     29:         
                     30:     
                     31: class uploadATFThread:
                     32:     """class for checking the files befor uploading"""
                     33:     
1.2     ! dwinter    34:     DEBUG=True
        !            35:     
1.1       dwinter    36:     def checkFile(self,filename,data,folder):
                     37:         """check the files"""
                     38:         # first check the file name
                     39:         fn=filename.split(".") # no extension
                     40:     
                     41:         if not (fn[0][0]=="P" or fn[0][0]=="S"):
                     42:             return False,"P/S missing in the filename"
                     43:         elif len(fn[0])!=7:
                     44:             return False,"P number has not the right length 6"
                     45:         elif not checkUTF8(data):
                     46:             return False,"not utf-8"
                     47:         else:
                     48:             return True,""
                     49:            
                     50:     def splitatf(self,fh,dir=None,ext=None):
                     51:         """split it"""
                     52:         ret=None
                     53:         nf=None
                     54:         i=0
                     55:         fileCount=0
                     56:         #ROC: why split \n first and then \r???
                     57:         if isinstance(fh, basestring):
                     58:             iter=fh.split("\n")
                     59:         else:
                     60:             iter=fh.readlines()
                     61:             
                     62:         for lineTmp in iter:
1.2     ! dwinter    63:             if (self.DEBUG==True) and (fileCount>10):
        !            64:               break;
1.1       dwinter    65:             lineTmp=lineTmp.replace(codecs.BOM_UTF8,'') # make sure that all BOM are removed..
                     66:             for line in lineTmp.split("\r"):
                     67:                 #logging.info("Deal with: %s"%line)
                     68:                
                     69:                 i+=1
                     70:                 if (i%100)==0:
                     71:                     self.result.write(str(i)+"\n")
                     72:                     self.result.flush()
                     73:                 #check if basket name is in the first line
                     74:                 if line.find("#atf basket")>=0: #old convention
                     75:                     ret=line.replace('#atf basket ','')
                     76:                     ret=ret.split('_')[0]
                     77:                 elif line.find("#basket:")>=0: #new convention
                     78:                     ret=line.replace('#basket: ','')
                     79:                     ret=ret.split('_')[0]
                     80:     
                     81:                 else:
                     82:                     if (len(line.lstrip())>0) and (line.lstrip()[0]=="&"): #newfile
                     83:                         if nf:
                     84:                             fileCount+=1
                     85:                             print fileCount
                     86:                             nf.close() #close  file
1.2     ! dwinter    87:                             if (self.DEBUG==True) and (fileCount>10):
        !            88:                               break
1.1       dwinter    89:     
                     90:                         filename=line[1:].split("=")[0].rstrip()+".atf"
                     91:                         if dir:
                     92:                             filename=os.path.join(dir,filename)
                     93:                         nf=file(filename,"w")
                     94:                         logging.debug("open %s"%filename)
                     95:                     if nf:    
                     96:                         nf.write(line.replace("\n","")+"\n")
                     97:     
                     98:         try:        
                     99:             nf.close()
                    100:             
                    101:         except:
                    102:             pass
                    103:         
                    104:         if not isinstance(fh, basestring):
                    105:             fh.close()
                    106:         
                    107:         files = os.popen4('find %s' % dir)[1].read().rstrip().split('\n')
                    108:         files.remove(dir)
                    109:        
                    110:         return ret,len(files)
                    111:         
                    112: 
                    113:     def __init__(self):
                    114:         """initialise"""
                    115:         logging.getLogger().setLevel(logging.DEBUG)
                    116:         
                    117:         
1.2     ! dwinter   118:     def set(self,uploadId,basketId,username,serverport="29080"):
1.1       dwinter   119:         """set start values for the thread"""
                    120:         self.result=file("/tmp/"+str(uploadId)+".out","w")
                    121:         self.uploadId=uploadId
                    122:         self.basketId=basketId
                    123:         self.username=username
                    124:         self.serverport=serverport
                    125:       
                    126:         
                    127:     def __call__(self):
                    128:         """call method """
                    129:         self.run()
                    130:         return True
                    131:     
                    132:     def getContext(self, app,serverport="8080"):
                    133:         """get the context within the ZODB"""
                    134:         resp = HTTPResponse(stdout=None)
                    135:         env = {
                    136:             'SERVER_NAME':'localhost',
                    137:             'SERVER_PORT':serverport,
                    138:             'REQUEST_METHOD':'GET'
                    139:             }
                    140:         req = HTTPRequest(None, env, resp)
                    141:         return app.__of__(RequestContainer(REQUEST = req))
                    142:         
                    143:     def run(self):
                    144:        
                    145:      
                    146:         #find context within ZODB
                    147:         storage=ClientStorage.ClientStorage(("localhost",8100));
                    148:         db = DB(storage)
                    149:         conn = db.open()
                    150:         root = conn.root()
                    151:         app  = root['Application']
                    152:         ctx = self.getContext(app,serverport=self.serverport)
                    153:         logging.info("run intern")
                    154:        
                    155:         logging.info("call thread intern")
                    156:         self.uploadATFThread(ctx,self.uploadId,self.basketId)
                    157:      
                    158:         #ctx.cdliRoot.cdli_main.tmpStore2[self.getName()[0:]]=self.returnValue
                    159:         
                    160:         
                    161:         
                    162:     def getResult(self):
                    163:         """method for accessing result"""
                    164:         ret=""
                    165:         for x in self.result.readlines():
                    166:             ret+=x
                    167:             
                    168:         return ret
                    169:     
                    170:     def uploadATFThread(self,ctx,uploadId,basketId=0):
                    171:         """upload an atf file"""
                    172:         #TODO: add comments
                    173:         #TODO: finish uploadATF
                    174:         
                    175:         
                    176:         logging.info("start, upload thread")
                    177:         self.result.write("<html><body><h2>I got your file, start now to split it into single atf-files!</h2><p>\n")
                    178:     
                    179:         #make sure that id is a string and not an integer
                    180:         basketId=str(basketId)
                    181:         logging.info("basketID:"+basketId)
                    182:         #TODO: make this configurable, at the moment, rootFolder for cdli has to be cdliRoot
                    183:         ctx2=ctx.cdliRoot
                    184:         
                    185:         #get temporary file for staging the downloaded and splitted files
                    186:         dir=tempfile.mkdtemp()
                    187:         
                    188:         logging.info("tmpfFile:"+str(dir))
                    189:         changed=[] # changed files
                    190:         errors=[]  # files with errors
                    191:         lockerrors=[]  # files with errors
                    192: 
                    193:         newPs=[]   # new p filed
                    194:         psNotInCatalog=[] # files not in the catalog
                    195:         
                    196:         #split the uploadedd atf file
                    197:         logging.info("start splitting")
                    198:         basketNameFromFile,numberOfFiles=self.splitatf(file("/tmp/"+uploadId,'r'),dir)
                    199:         
                    200:         #find basketId if not set
                    201:         
                    202:         #get active abaket
                    203:         if basketId == '0':
                    204:             print ctx2
                    205:             basketObj=ctx2.basketContainer.getActiveBasket()
                    206:             if basketObj:
                    207:                 basketId=basketObj.getId()
                    208:                 
                    209:         #if there is no active basket and no basketid given, id is empty, else get besketname and length
                    210:         if basketId == '0':
                    211:             basketNameFromId=""
                    212:             basketLen=0
                    213:         else:
                    214:             basketNameFromId=getattr(ctx2.basketContainer,basketId).title
                    215:             basketLen=getattr(ctx2.basketContainer,basketId).getLastVersion().numberOfItems()
                    216:             
                    217:         logging.info("got the file, upload thread")
                    218:         self.result.write("""<html><body><h2>I got the files</h2><
                    219:                         p>I am computing the differences to the exisiting files</p>\n""")
                    220:                                    
                    221:         #start to check the files
                    222:         
                    223:         #workaround fuer memory fehler in listdir 
                    224:         #http://stackoverflow.com/questions/4098831/workaround-oserror-with-os-listdir
                    225:         files = os.popen4('find %s' % dir)[1].read().rstrip().split('\n')
                    226:         files.remove(dir)
                    227:         n = len(dir)
                    228:         if dir[-1] != os.path.sep:
                    229:             n += 1
                    230:             files = [f[n:] for f in files] # remove dir prefix
                    231: 
                    232:         #for fn in os.listdir(dir):
                    233:         for fn in files:
                    234:             
                    235:             self.result.write("<p>process:%s</p>\n"%fn)
                    236:             logging.debug(fn)
                    237:             # check if file is in the catalog
                    238:             #TODO: checkCatalog is not implemented yet
                    239:             if ctx2.cdli_main.checkCatalog(fn):
                    240:                 psNotInCatalog.append(fn)
                    241:                 
                    242:             #check if p-file already at the server  
                    243:             founds=ctx2.CDLICatalog.search({'title':fn})    
                    244:       
                    245:             #if not than add filename to the list of newfiles
                    246:             dataFile=file(os.path.join(dir,fn))
                    247:             data=dataFile.read()
                    248:             dataFile.close()
                    249:             status,msg=self.checkFile(fn,data,dir)
                    250:             #status=True
                    251:             
                    252:             
                    253:             if not status: # error
                    254:                 errors.append((fn,msg))
                    255:             
                    256:             else:
                    257:                 if len(founds)==0:
                    258:                     newPs.append(fn)
                    259: 
                    260:                 #if p file alread at the server    
                    261:                 for found in founds:
                    262:                     #analyse the differences to the actual file
                    263:                     obj=found.getObject()
                    264: 
                    265:                     if (not (str(obj.lockedBy))=='') and (not (str(obj.lockedBy)==str(self.username))):
                    266:                                 lockerrors.append((fn,str(obj.lockedBy)))
                    267:                     else:
                    268:                 
                    269:                         diffs=obj.diff(data)
                    270:                         if diffs[0]>0:
                    271:                             changed.append((obj,diffs)) #hochladen
                    272: 
                    273:         #ready, set the returnValues
                    274:         self.result.write("<h3>Done</h3></body></html>\n")
                    275:         
                    276:         stObj = StoreObject(uploadId);
                    277:         
                    278:         stObj.returnValue={}
                    279:         
                    280:         stObj.returnValue['errors']=errors
                    281:         
                    282:         stObj.returnValue['newPs']=newPs
                    283:         stObj.returnValue['tmpdir']=dir
                    284:         stObj.returnValue['basketLen']=basketLen
                    285:         stObj.returnValue['numberOfFiles']=numberOfFiles
                    286:         stObj.returnValue['basketNameFromId']=basketNameFromId
                    287:         stObj.returnValue['basketNameFromFile']=basketNameFromFile
                    288:         stObj.returnValue['basketId']=basketId
                    289:         stObj.returnValue['dir']=dir
                    290:         #stObj.returnValue['changed']=copy.copy(changed)
                    291:         stObj.returnValue['changed']=[(x[0].getId(),x[1][0]) for x in changed]
                    292:         #stObj.returnValue['lockerrors']=[x[0].getId() for x in lockerrors]
                    293:         stObj.returnValue['lockerrors']=[x for x in lockerrors]
                    294:         self.returnValue=True
                    295:         #ctx2.cdli_main.setTemp('v_uploadATF_returnValue',True)
                    296:  
                    297:         stObj.save();
                    298:  
                    299: def checkUTF8(data):
                    300:     """check utf 8"""
                    301:     if not isinstance(data, str):
                    302:         logging.error("checkUTF8 data is not string! (%s)"%repr(data))
                    303: 
                    304:     try:
                    305:         data.decode('utf-8')
                    306:         logging.debug("checkUTF8: ok!")
                    307:         return True
                    308:     except:
                    309:         logging.debug("checkUTF8: false!")
                    310:         return False
                    311:            
                    312: if __name__ == "__main__":
1.2     ! dwinter   313:        if len(sys.argv)<5:
        !           314:            print """Usage: procedure uploadId comment basketName unlock username
        !           315:            uploadId: Ticket ID von uploadATF
        !           316:            basketName: name of the basket
        !           317:            username: username
        !           318:            port of a running zope (not the zeo)
        !           319:            """
        !           320:         
1.1       dwinter   321:        upload = uploadATFThread()
                    322:        x=sys.argv;
                    323:        print x
                    324:        upload.set(sys.argv[1],sys.argv[2],sys.argv[3],sys.argv[4])
                    325:        upload.run();

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>