class XNATScenePackager(object): """Class containing methods for packaging scenes pertinent to the Slicer-XNAT workflow. The major feature of this class is that it handles any shared nodes and 1) uploads them to a "shared" folder on XNAT 2) eliminates them from scene packages sent to XNAT.""" def __init__(self, browser = None): self.browser = browser self.viewer = self.browser.XNATView self.utils = XNATUtils() self.hostName = 'https://central.xnat.org' def determineSceneType(self): scene = slicer.app.mrmlScene() currURL = os.path.normpath(scene.GetURL()) if currURL == None or currURL == '': return None elif currURL.find(self.utils.projectPath) == 0: return "XNATSlicerScene" else: return "LocalScene" return None def bundleScene(self, args): # # STEP 1: Init variables. # XNATCommunicator = args['XNATCommunicator'] XNATDir = args['saveDir'] XNATSharedDir = args['sharedDir'] sceneName = args['fileName'] metadata = args['metadata'] packageName = os.path.basename(sceneName.split(".")[0]) # # STEP 2: Analyzes the scene type. # #print self.utils.lf() + "ANALYZING SCENE TYPE" sceneType = self.determineSceneType() #print self.utils.lf() + "SCENE TYPE: %s"%(sceneType) # # STEP 3: Create a directory for packaging. # tempDir = os.path.join(self.utils.tempUploadPath, packageName) #print self.utils.lf() + "CREATE PACKAGE DIRECTORY: %s"%(tempDir) try: #print self.utils.lf() + ("%s does not exist. Making it."%(tempDir)) self.utils.removeFilesInDir(tempDir) os.rmdir(tempDir) except Exception, e: pass try: os.mkdir(tempDir) except Exception, e: pass # # STEP 4: Write according to scene type and if there's matching metadata. # #print self.utils.lf() + "BEGINNING THE SCENE WRITE" self.browser.updateStatus(["", "Write all...", ""]) #print self.utils.lf() + "WRITING ALL!" self.writeScene_All(tempDir) slicer.app.processEvents() self.browser.updateStatus(["", "Finding mrml...", ""]) mrml = None for root, dirs, files in os.walk(tempDir): for relFileName in files: if relFileName.endswith("mrml"): mrml = os.path.join(root, relFileName) break slicer.app.processEvents() self.browser.updateStatus(["", "Bundling scene. Please wait...", ""]) return {'path':self.utils.adjustPathSlashes(tempDir), 'mrml': self.utils.adjustPathSlashes(mrml)} # SOURCE OF FOLLOWING CODE: # http://stackoverflow.com/questions/296499/how-do-i-zip-the-contents-of-a-folder-using-python-version-2-5 # # NOTE: To be deprecated after MRB methods are put in place. def zipdir(self, basedir=None, zipArchive=None): assert os.path.isdir(basedir) with closing(ZipFile(zipArchive, "w", ZIP_DEFLATED)) as z: for root, dirs, files in os.walk(basedir): #NOTE: ignore empty directories for fn in files: absfn = os.path.join(root, fn) zfn = absfn[len(basedir)+len(os.sep):] #XXX: relative path z.write(absfn, zfn) def packageDir(self, packageFilePath, sceneDir): #logic = slicer.app.applicationLogic() #logic.SaveSceneToSlicerDataBundleDirectory(sceneDir, None) slicer.app.applicationLogic().Zip(packageFilePath,sceneDir) def writeScene_All(self, saveDir): #slicer.app.processEvents() if os.path.exists(saveDir): self.utils.removeDirsAndFiles(saveDir) #slicer.app.processEvents() try: os.makedirs(saveDir + "/Data") except Exception, e: print self.utils.lf() + "Likely the dir already exists: " + str(e) slicer.app.applicationLogic().SaveSceneToSlicerDataBundleDirectory(saveDir, None) slicer.app.processEvents()
class XNATSaveWorkflow(object): def __init__(self, browser, XNATCommunicator, sessionArgs): """ Parent class of any load workflow """ self.browser = browser self.scenePackager = XNATScenePackager(self.browser) self.utils = XNATUtils() self.sessionArgs = sessionArgs self.XNATCommunicator = XNATCommunicator def saveScene(self): #======================================================================= # PACKAGE SCENE # # NOTE: The scene packager refers to the .metadata file. #======================================================================= package = self.scenePackager.bundleScene(self.sessionArgs) projectDir = package['path'] mrmlFile = package['mrml'] #======================================================================= # ZIP PACKAGE #======================================================================= self.browser.updateStatus(["Compressing package. Please wait...", "", ""]) packageFileName = projectDir + self.utils.defaultPackageExtension if os.path.exists(packageFileName): self.utils.removeFile(packageFileName) self.scenePackager.packageDir(packageFileName, projectDir) self.browser.updateStatus(["Deleting temporary package.", "", ""]) self.utils.removeDirsAndFiles(projectDir) #======================================================================= # UPLOAD PACKAGE #======================================================================= self.browser.updateStatus(["Sending '%s' to XNAT. Please wait..."% (os.path.basename(packageFileName)), "", ""]) #print ("UPLOADING HERE: " + self.sessionArgs['saveDir'] + "/" + os.path.basename(packageFileName)) self.XNATCommunicator.upload(packageFileName, self.sessionArgs['saveDir'] + "/" + os.path.basename(packageFileName)) slicer.app.processEvents() if self.sessionArgs['sharable']: self.browser.updateStatus(["", "Finished updating '%s' in XNAT."% (os.path.basename(packageFileName)), ""]) else: self.browser.updateStatus(["", "Finished writing '%s' to XNAT."% (os.path.basename(packageFileName)), ""]) #======================================================================= # UPDATE VIEWER #======================================================================= self.sessionArgs['sessionType'] = "scene upload" self.browser.XNATView.startNewSession(self.sessionArgs) self.browser.XNATView.loadButton.setEnabled(True) self.browser.XNATView.deleteButton.setEnabled(True) self.browser.XNATView.setCurrItemToChild(item = None, childFileName = os.path.basename(packageFileName)) def determineSaveLocation(self, itemType, selectedDir, saveLevel = None): """ Method goes through various steps to determine the optimal XNAT location to save the current scene. """ #======================================================================= # SET VARIABLES #======================================================================= print self.utils.lf() + "DETERMINE SAVE DIR" currDir = os.path.dirname(selectedDir) saveDir = "" #======================================================================= # NONE HANDLER #======================================================================= if not saveLevel: # This is where another analysis step could exist to determine where # the scene could be saved. saveLevel = self.utils.defaultXNATSaveLevel #======================================================================= # CHECK SAVE LEVEL VALIDITY #======================================================================= else: findCount = False for key, value in self.utils.xnatDepthDict.iteritems(): if value == saveLevel: findCount = True if not findCount: print (self.utils.lf() + "Couldn't find save level '%s'. Resorting to default: %s"%(saveLevel, self.utils.defaultXNATSaveLevel)) saveLevel = self.utils.defaultXNATSaveLevel # Look at the sessionManager, reconcile save dir based on that # and XNATSaveLevel if self.browser.XNATView.sessionManager.currSessionInfo: saveDir = self.utils.getSlicerDirAtLevel(self.browser.XNATView.sessionManager.currSessionInfo['RemoteURI'], saveLevel) else: return None print "SAVEDIR: " + saveDir otherRequiredDirs = [] baseDir = saveDir.split(self.utils.slicerDirName)[0] for folderName in self.utils.requiredSlicerFolders: otherRequiredDirs.append("%s%s/files/"%(baseDir, folderName)) return {'saveDir': saveDir, 'others': otherRequiredDirs}