1
2 import zipfile
3 import os
4 import empro
5
6 if zipfile.zlib:
7 _COMPRESSION = zipfile.ZIP_DEFLATED
8 else:
9 _COMPRESSION = zipfile.ZIP_STORED
10
11
12 ALL, SETUP = "all", "setup"
13 ZEP, UNZEP = "zep", "unzep"
18 '''
19 decorator to print exception to output before reraising it.
20 '''
21 def op(*args, **kwargs):
22 try:
23 return func(*args, **kwargs)
24 except:
25 import traceback
26 traceback.print_exc()
27 raise
28 return op
29
30
31
32 -def zep(iTarget, iWhat=ALL, iDirectory=None, iUpdateCb=None):
33 """
34 zep(iTarget, iWhat, iDirectory). Packs the EMPro project into a .zep file that can be easily transported.
35 iTarget : target file
36 iWhat : What to zep {All, Setup }
37 iDirectory: project directory to use (None=current project)
38 iUpdateCb: callback for progress, it takes the full path of the filename being compressed
39 """
40 if iDirectory==None:
41 iDirectory = empro.activeProject.rootDir
42 largeFile = _dirSize( iDirectory, iWhat) > (4294967296/2)
43 zip = zipfile.ZipFile(iTarget, 'w', _COMPRESSION, allowZip64=largeFile)
44 for path in _listDir(iDirectory, iWhat):
45 name = path[len(os.path.dirname(iDirectory)):].lstrip(os.sep + (os.altsep or ''))
46 zip.write(path, name)
47 if iUpdateCb:
48 iUpdateCb(path)
49
50
51 -def unzep(iTarget, iWhat, iDirectory=None, iUpdateCb=None, prefix=None):
52 """
53 unzep
54 """
55 assert zipfile.is_zipfile(iTarget), u"%r is not a valid ZEP/ZIP file" % iTarget
56 dkzip = zipfile.ZipFile(iTarget)
57 nameList = dkzip.namelist()
58 root = os.path.normpath(os.path.dirname(os.path.commonprefix(nameList)))
59 chosenFilter = _makeFilter(iWhat, root)
60 for name in nameList:
61 if name.endswith('/'):
62 continue
63 if not chosenFilter(name):
64 continue
65 subdir, filename = os.path.split(name)
66 if prefix:
67 assert subdir.startswith(root), "%r does not start with %r" % (subdir, root)
68 subdir = os.path.join(prefix, subdir[len(root):].lstrip('/'))
69 dirname = os.path.join(iDirectory, subdir)
70 if not os.path.exists(dirname):
71 os.makedirs(dirname)
72 cwd = os.getcwdu()
73 try:
74 os.chdir(dirname)
75 f = open(filename, 'wb')
76 f.write(dkzip.read(name))
77 f.close()
78 finally:
79 os.chdir(cwd)
80 if iUpdateCb:
81 iUpdateCb(os.path.join(dirname, filename))
82 return nameList
83
86 z = ZepGui(iZepOrUnzep=ZEP,iDefaultZep=iDefaultZep,iDefaultProj=iDefaultProj)
87 z.show()
88
89
90 -def unZepShowGUI(iDefaultZep="",iDefaultProj="",iDefaultOpen=None):
91 z = ZepGui(iZepOrUnzep=UNZEP,iDefaultZep=iDefaultZep,iDefaultProj=iDefaultProj,iDefaultOpen=iDefaultOpen)
92 z.show()
93
96 _sessionLastZepFile = ""
97 _sessionLastProjectDir = ""
98 _sessionLastActiveProject = ""
99 - def __init__(self,iDim=((60,60),(500,100)),iZepOrUnzep=ZEP,iDefaultZep="",iDefaultProj="",iDefaultOpen=None):
100 from empro.gui import SimpleDialog, Widget, PushButton, PushButton, LineEdit, Ok, Cancel, GridLayout, Label, CheckBox
101 self.action = iZepOrUnzep
102 self.dialog = SimpleDialog(Ok+Cancel)
103 self.dialog.setButtonText(Ok, {ZEP:"Zep", UNZEP:"Unzep"}[self.action])
104 self.dialog.title = {ZEP:"Archive a project", UNZEP:"Unarchive a project"}[self.action]
105 self.dialog.windowFlags -= empro.gui.WF_WindowStaysOnTopHint
106 self.mainWidget = Widget()
107 self.mainWidget.minimumWidth = iDim[1][0]-iDim[0][0]
108 self.mainWidget.minimumHeight = iDim[1][1]-iDim[0][1]
109 self.mainWidget.layout = GridLayout()
110 self.mainLayout = self.mainWidget.layout
111
112 if iZepOrUnzep == ZEP:
113 self.projectDir = iDefaultProj or ((ZepGui._sessionLastActiveProject == empro.activeProject.rootDir) and ZepGui._sessionLastProjectDir) or ""
114 self.zepFile = iDefaultZep or ((ZepGui._sessionLastActiveProject == empro.activeProject.rootDir) and ZepGui._sessionLastZepFile) or ""
115 if not self.projectDir and empro.activeProject.rootDir:
116 self.projectDir = empro.activeProject.rootDir
117 projectName = empro.activeProject.name
118 self.zepFile = os.path.join(os.path.dirname(empro.activeProject.rootDir), projectName) + '.zep'
119 else:
120 self.zepFile = iDefaultZep or ZepGui._sessionLastZepFile
121 self.projectDir = iDefaultProj or ZepGui._sessionLastProjectDir or _lastUnZepLocation()
122
123 self.edtProjectDir = LineEdit(self.projectDir, {ZEP:"Project Directory:", UNZEP:"Destination Directory:"}[self.action] )
124 self.moreDirsButton = PushButton("Browse...")
125 self.moreDirsButton.onClicked = self.onMoreDirs
126 self.edtZepFile = LineEdit(self.zepFile, "Zep File:" )
127 self.morePathsButton = PushButton("Browse...")
128 self.morePathsButton.onClicked = self.onMoreZeps
129 self.lblSize = Label("(0 kB)")
130 self.lastSize = 0
131 for w in [self.edtProjectDir, self.edtZepFile]:
132 w.layout.contentsMargin = (0,0,0,0)
133
134 if self.action==ZEP:
135 self.mainLayout.addWidget(self.edtProjectDir,0,0)
136 self.mainLayout.addWidget(self.lblSize,0,1)
137 self.mainLayout.addWidget(self.moreDirsButton,0,2)
138 self.mainLayout.addWidget(self.edtZepFile,1,0,1,2)
139 self.mainLayout.addWidget(self.morePathsButton,1,2)
140 else:
141 self.mainLayout.addWidget(self.edtZepFile,0,0)
142 self.mainLayout.addWidget(self.lblSize,0,1)
143 self.mainLayout.addWidget(self.morePathsButton,0,2)
144 self.mainLayout.addWidget(self.edtProjectDir,1,0,1,2)
145 self.mainLayout.addWidget(self.moreDirsButton,1,2)
146
147 self.checkSimulationResults = CheckBox(u"%s simulation results" % {ZEP:"Archive", UNZEP:"Unarchive"}[self.action])
148 self.checkSimulationResults.checked = empro.core.ApplicationPreferences.getPreference(_PREFERENCE_ZEP_INCLUDE_SIMULATIONS, "1") not in ("0", "false")
149 self.checkSimulationResults.onStateChanged = self.onArchiveSimResults
150 self.mainLayout.addWidget(self.checkSimulationResults,2,0)
151
152 if self.action == UNZEP:
153 self.checkOpenAfterUnzep = CheckBox("Open Project after Unarchiving")
154 self.useOpenAfterUnzepPreference = iDefaultOpen is None
155 if self.useOpenAfterUnzepPreference:
156 iDefaultOpen = empro.core.ApplicationPreferences.getPreference(_PREFERENCE_ZEP_OPEN_PROJECT, "1") not in ("0", "false")
157
158 self.checkOpenAfterUnzep.checked = iDefaultOpen
159 self.mainLayout.addWidget(self.checkOpenAfterUnzep,3,0)
160 else:
161 self.checkOpenAfterUnzep = None
162
163 self.mainLayout.contentsMargin = (0,0,0,0)
164 self.dialog.layout.add(self.mainWidget)
165 self.updateSize()
166 self.dialog.onFinished = self.onFinished
167
170
172 try:
173 if self.action==ZEP:
174 assert _isValidProjectDir(self.projectDir)
175 self.lastSize = _dirSize(self.projectDir, {True:"All", False: "Setup"}[self.checkSimulationResults.checked])
176 else:
177 self.lastSize = os.path.getsize(self.zepFile)
178 mbsize = self.lastSize / (1024.0*1024.0)
179 self.lblSize.text = "( %4.1fMb)" % mbsize
180 except:
181 self.lblSize.text = self.lastSize = "(invalid)"
182
183 @_printexception
185 defaultRoot = self.edtProjectDir.text or _lastUnZepLocation()
186 if self.action == ZEP:
187 newDir = empro.gui.getOpenPathOA(self.dialog, "Select EMPro Project", defaultRoot, "AllEMProProjects", "Select")
188 else:
189 newDir = empro.gui.getOpenPathOA(self.dialog, "Select Destination", defaultRoot, "RegularFolder | OALibrary", "Select")
190 if not newDir:
191 return
192 self.edtProjectDir.text = self.projectDir = os.path.normpath(newDir)
193 if self.action == ZEP:
194 self.updateSize()
195 if not self.zepFile and self.projectDir:
196 dirname, basename = os.path.split(self.projectDir)
197 self.edtZepFile.text = self.zepFile = os.path.join(dirname, os.path.splitext(basename)[0] + '.zep')
198 else:
199 _lastUnZepLocation(self.projectDir)
200
201 @_printexception
203 newZep = ""
204 if self.action==ZEP:
205 newZep = empro.gui.getSavePathOA(self.dialog, "Select Zep File to archive project to", self.zepFile or _lastZepLocation(),"ZepFile", "Select")
206 else:
207 newZep = empro.gui.getOpenPathOA(self.dialog, "Select Zep File to extract project from",self.zepFile or _lastZepLocation(),"ZepFile", "Select")
208 if not newZep:
209 return
210 self.edtZepFile.text = self.zepFile = os.path.normpath(newZep)
211 _lastZepLocation(os.path.dirname(self.zepFile))
212 if self.action == UNZEP:
213 self.updateSize()
214
215 @_printexception
217 import time
218 import empro
219 from empro import gui
220 from empro.toolkit.gui import InfoDialog, YesNoDialog
221 if iReturn != gui.SimpleDialog.Accepted:
222 return
223
224 empro.core.ApplicationPreferences.setPreference(_PREFERENCE_ZEP_INCLUDE_SIMULATIONS, self.checkSimulationResults.checked)
225 if self.checkOpenAfterUnzep and self.useOpenAfterUnzepPreference:
226 empro.core.ApplicationPreferences.setPreference(_PREFERENCE_ZEP_OPEN_PROJECT, self.checkOpenAfterUnzep.checked)
227 self.projectDir = self.edtProjectDir.text
228 if self.action == UNZEP:
229 _lastUnZepLocation(self.projectDir)
230
231 self.zepFile = self.edtZepFile.text
232 ZepGui._sessionLastProjectDir = self.projectDir
233 ZepGui._sessionLastZepFile = self.zepFile
234 ZepGui._sessionLastActiveProject = empro.activeProject.rootDir
235
236 if self.action == ZEP:
237 if not os.path.exists(self.projectDir):
238 gui.MessageBox.critical( "Archive", u"%s\nPath does not exist.\nCheck the project directory and try again." % self.projectDir, gui.Ok, gui.Ok )
239 return
240 if not _isValidProjectDir(self.projectDir):
241 gui.MessageBox.critical( "Archive", u"%s\nPath is not a valid EMPro project.\nCheck the project directory and try again." % self.projectDir, gui.Ok, gui.Ok )
242 return
243 if os.path.isdir(self.zepFile):
244 self.zepFile = os.path.join(self.zepFile, os.path.basename(self.projectDir))
245 if self.zepFile.lower().endswith('.ep'):
246 self.zepFile = self.zepFile[:-3] + ".zep"
247 else:
248 self.zepFile += ".zip"
249 if os.path.dirname( self.zepFile ) and not os.path.isdir( os.path.dirname( self.zepFile ) ):
250 gui.MessageBox.critical( "Archive", u"%s\nPath does not exist.\nCheck the zep file and try again." % self.zepFile, gui.Ok, gui.Ok )
251 return
252 if os.path.exists(self.zepFile):
253 if gui.MessageBox.question( "Archive", u"%s\nPath already exists.\nDo you want to replace it?" % self.zepFile, gui.Yes | gui.No, gui.No ) != gui.Yes:
254 return
255 os.remove(self.zepFile)
256 else:
257 if not os.path.exists(self.zepFile):
258 gui.MessageBox.critical( "Unarchive", u"%s\nPath does not exist.\nCheck the zep file and try again." % self.zepFile, gui.Ok, gui.Ok )
259 return
260 if not zipfile.is_zipfile(self.zepFile):
261 gui.MessageBox.critical( "Unarchive", u"%s\nPath is not a valid zep file.\nCheck the zep file and try again." % self.zepFile, gui.Ok, gui.Ok )
262 return
263 destDir = self.projectDir
264 if os.path.isfile( destDir ):
265 gui.MessageBox.critical( "Unarchive", u"%s\nPath is not a directory.\nCheck the destination directory and try again." % destDir, gui.Ok, gui.Ok )
266 return
267 namelist = zipfile.ZipFile(self.zepFile).namelist()
268 commonDir = os.path.normpath(os.path.dirname(os.path.commonprefix(namelist)))
269
270 if os.path.dirname(commonDir):
271
272 gui.MessageBox.critical( "Unarchive", u"%s\nZep file does not contain an EMPro project.\nCheck the zep file and try again." % self.zepFile, gui.Ok, gui.Ok )
273 return
274 if commonDir.endswith(".ep"):
275
276 projectFile = os.path.join(commonDir, "Project.xml")
277 if not projectFile in map(os.path.normpath, namelist):
278 projectFile = os.path.join(commonDir, "eesof_empro.xml")
279 if not projectFile in map(os.path.normpath, namelist):
280 gui.MessageBox.critical( "Unarchive", u"%s\nZep file does not contain an EMPro project.\nCheck the zep file and try again." % self.zepFile, gui.Ok, gui.Ok )
281 return
282 if not os.path.exists( destDir ):
283 try:
284 os.makedirs( destDir )
285 except OSError as error:
286 gui.MessageBox.critical( "Unarchive", u"%s\nFailed to create path:\n%s\nCheck the destination directory and try again." % (self.projectDir, os.strerror(error.errno)), gui.Ok, gui.Ok )
287 renamePrefix = None
288 else:
289
290 import ariane
291 projectFile = os.path.join(commonDir, "empro", "eesof_empro.xml")
292 if not projectFile in map(os.path.normpath, namelist):
293 projectFile = os.path.join(commonDir, "empro", "Project.xml")
294 if not projectFile in map(os.path.normpath, namelist):
295 gui.MessageBox.critical( "Unarchive", u"%s\nZep file does not contain an EMPro project.\nCheck the zep file and try again." % self.zepFile, gui.Ok, gui.Ok )
296 return
297 cellName = _nativeName(commonDir)
298
299 if not cellName:
300 gui.MessageBox.critical( "Unarchive", u"%s\nZep contains an EMPro project with an invalid cellname.\nCheck the zep file and try again." % self.zepFile, gui.Ok, gui.Ok )
301 return
302 library, destDir = self._enforceLibrary( destDir, os.path.basename( self.zepFile ) )
303 if not library:
304 return
305
306 try:
307 commonDir = library.getFileSystemNameSpace().fromNativeName(cellName)
308 except Exception, error:
309 gui.MessageBox.critical( "Unarchive", u"%s\nEMPro project has an invalid cellname.\nCheck the zep file and try again." % cellName, gui.Ok, gui.Ok )
310 return
311
312 projectDir = os.path.join(destDir, commonDir)
313 if os.path.exists(projectDir):
314 if gui.MessageBox.question( "Unarchive", u"%s\nPath already exists.\nDo you want to replace it?" % projectDir, gui.Yes | gui.No, gui.No ) != gui.Yes:
315 return
316 import shutil
317 try:
318 shutil.rmtree(projectDir)
319 except OSError as error:
320 gui.MessageBox.critical( "Unarchive", u"%s\nFailed to delete destination directory:\n%s\nDelete it manually and try again." % (projectDir, os.strerror(error.errno)), gui.Ok, gui.Ok )
321 return
322
323 self.alreadyZipped = 0
324 self.alreadyUnZipped = 0
325 self.isCanceled = False
326 self.progressDialog = gui.SimpleDialog(gui.Cancel)
327 self.progressDialog.onFinished = self.onProgressFinished
328 self.progressDialog.title = {ZEP:"Zepping", UNZEP:"Unzepping"}[self.action] + " your project"
329 self.progressLabel = gui.Label("")
330 mbsize = self.lastSize/ (1024.0*1024.0)
331 if self.action == ZEP:
332 self.progressDialog.layout.add(gui.Label(u"Archiving the project in %s (%4.1fMb)" % (self.projectDir, mbsize )))
333 else:
334 self.progressDialog.layout.add(gui.Label(u"Unarchiving the project in %s (%4.1fMb)" % (destDir, mbsize )))
335 self.progressDialog.layout.add(self.progressLabel)
336 self.progressDialog.show(False)
337 startTime = time.time()
338 try:
339 whatToArchive = {True:ALL, False:SETUP}[self.checkSimulationResults.checked]
340 if self.action == ZEP:
341 zep(self.zepFile, whatToArchive, iDirectory=self.projectDir, iUpdateCb=self.progressZep)
342 del self.progressDialog
343 else:
344 try:
345 extractionList = unzep(self.zepFile, whatToArchive, iDirectory=destDir, iUpdateCb=self.progressUnZep, prefix=commonDir)
346 except OSError as error:
347 gui.MessageBox.critical( self.progressDialog, "Unarchive", u"%s\nFailed to extract project to directory:\n%s\nCheck the destination directory and try again." % (self.projectDir, os.strerror(error.errno)), gui.Ok, gui.Ok )
348 return
349 finally:
350 del self.progressDialog
351 if self.isCanceled:
352 return
353 if not self.checkOpenAfterUnzep.checked:
354 return
355 projectName = projectDir.replace("/",os.path.sep).strip().replace(os.path.sep,"/")
356 empro.activeProject.loadActiveProjectFrom(projectName)
357 ZepGui._sessionLastProjectDir = ""
358 ZepGui._sessionLastZepFile = ""
359 ZepGui._sessionLastActiveProject = ""
360 finally:
361
362 if time.time()-startTime<2.0:
363 time.sleep(2.0-(time.time()-startTime))
364
366 try:
367 self.alreadyZipped += os.path.getsize(path)
368 msize = self.alreadyZipped
369 perc = msize*100.0/self.lastSize
370 self.progressLabel.text = "%3d%% completed." % perc
371 self.progressLabel.update()
372 empro.gui.processEvents()
373 except:
374 import traceback
375 traceback.print_exc()
376 finally:
377 return not self.isCanceled
378
380 try:
381 self.alreadyUnZipped += os.path.getsize(path)
382 mbsize = self.alreadyUnZipped/1000000.0
383 self.progressLabel.text = "%4.1fMb extracted." % mbsize
384 self.progressLabel.update()
385 empro.gui.processEvents()
386 except:
387 import traceback
388 traceback.print_exc()
389 finally:
390 return not self.isCanceled
391
393 self.isCanceled = retcode != empro.gui.SimpleDialog.Accepted
394
396 import os
397 import ariane
398 from empro import gui
399
400 candidates = [baseDir]
401 zepName = os.path.splitext(zepName)[0]
402 while zepName.endswith(".ep"):
403 zepName = zepName[:-3]
404 if zepName:
405 candidates.append(os.path.join(baseDir, zepName))
406
407
408 for libraryDir in candidates:
409 if not os.path.exists(libraryDir) or not os.listdir(libraryDir):
410
411 try:
412 return ariane.Library.create(libraryDir, os.path.basename(libraryDir) ), libraryDir
413 except Exception, error:
414 gui.MessageBox.critical( "Unarchive", u"%s\nFailed to create library:\n%s\nCheck the destination library and try again." % (libraryDir, error), gui.Ok, gui.Ok )
415 return None, None
416 if os.path.exists(os.path.join(libraryDir, ".oalib")):
417
418 try:
419 return ariane.Library.open(libraryDir, writeAccess=True ), libraryDir
420 except Exception, error:
421 gui.MessageBox.critical( "Unarchive", u"%s\nFailed to open library:\n%s\nCheck the destination library and try again." % (libraryDir, error), gui.Ok, gui.Ok )
422 return None, None
423
424 gui.MessageBox.critical( "Unarchive", u"Failed to open or create library in %s.\nCheck the destination or create a new library, and try again." % baseDir, gui.Ok, gui.Ok )
425 return None, None
426
428 self.dialog.show(True)
429
432 def isSimulationDir(path, root):
433 for p, r in zip(_fullySplitPath(path), _fullySplitPath(root)):
434 if p != r:
435 break
436 if p == r:
437 return False
438 if p == "Simulations":
439 return True
440 import re
441 if re.match(r'^\d{6}$', p):
442 return True
443 return False
444 filters = {
445 ALL: lambda path: True,
446 SETUP: lambda path, r=root+'/': not isSimulationDir(path, r),
447 }
448 return filters[what.lower()]
449
457
466
467 _lastZepLocation = lambda set_value=None: _lastLocation("lastZepLocation", set_value)
468 _lastUnZepLocation = lambda set_value=None: _lastLocation("lastUnZepLocation", set_value)
469
470
471 _PREFERENCE_ZEP_OPEN_PROJECT = "zepOpenProject"
472 _PREFERENCE_ZEP_INCLUDE_SIMULATIONS = "zepIncludeSimulations"
476 recursivelistdir = lambda directory: sum([[os.path.join(root, fname) for fname in fnames] for root, dirnames, fnames in os.walk(directory)], [])
477 what = what.lower()
478 if what == ALL:
479 return recursivelistdir(directory)
480 assert what == SETUP, what
481 import re
482 simId = re.compile(r'^\d{6}$')
483 files = []
484 for fname in os.listdir(directory):
485 path = os.path.join(directory, fname)
486 if os.path.isfile(path):
487 if fname != '.nextSimulationNumber':
488 files.append(path)
489 else:
490 if fname != 'Simulations' and not simId.match(fname):
491 files += recursivelistdir(path)
492 return files
493
499
502 if iDirectory.endswith(".ep"):
503 if os.path.exists(os.path.join(iDirectory, "eesof_empro.xml")):
504 return True
505 return os.path.exists(os.path.join(iDirectory, "Project.xml"))
506
507 libdir = os.path.dirname(os.path.abspath(iDirectory))
508 if not libdir:
509 return False
510 if os.path.exists(os.path.join(iDirectory, "empro", "eesof_empro.xml")):
511 return True
512 return os.path.exists(os.path.join(iDirectory, "empro", "Project.xml"))
513
516 import ariane
517 try:
518 return ariane.unixNameSpace().toNativeName(fsName)
519 except:
520 try:
521 return ariane.windowsNameSpace().toNativeName(fsName)
522 except:
523 return None
524
525
526 if __name__=="__main__":
527 zepShowGUI()
528