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