Source code for tools.project.incrementalArchive

#!/usr/bin/env python
# -*- coding: UTF-8 -*-

""" Module incrementalArchive: This module ... """

import logging
# noinspection PyUnresolvedReferences
import mari
import os
import traceback
from PySide.QtGui import QMessageBox, QFileDialog, QApplication
from stkMariTools.lib.ui_utils import MariToolsMenuItem


[docs]class IncrementalArchiveMenuItem(MariToolsMenuItem): """ This class adds a Clear History action. """ logger = logging.getLogger(__name__) def __init__(self): """ The constructor. :return: """ super(IncrementalArchiveMenuItem, self).__init__() # Set the class instance mari.IncrementalArchiveMenuItem = self # Action item is to be called in the Menu self.actionIdentifier = 'Archive current project (incremental)' # Python command to be run when action is executed from the Menu self.actionCommand = 'mari.IncrementalArchiveMenuItem.archiveProject()' # Path to the action in the Mari Menu self.actionPath = 'MainWindow/&Scripts/&Project/&Archives' # Icon to use for the action self.actionIcon = 'Folder' # Define metadata common attributes self.archive_location_metaId = 'archiveSavePath' self.archive_location_metaDescription = 'This attribute defines a common location ' \ 'where the archive is to be saved to ' \ 'on the local filesystem.' self.archive_version_metaId = 'archiveVersion' self.archive_version_metaDescription = 'This attribute defines the current archive version.' # Define amount of padding to use when formatting version strings self.version_padding = 3 # Add the item to the Mari Menu self.addMariToolsMenuItem()
[docs] def archiveProject(self): """ This method incrementally archives the current project. :return: """ current_project = mari.projects.current() if not current_project: self.logger.error('### No current project to archive could be returned!!!') mari.utils.message( text='You need to have a project open first in order to archive it!', title='No project currently open!', icon=QMessageBox.Icon.Warning, ) return # Store reference to UUID for being able to recall once project has been closed project_uuid = current_project.uuid() # Check for existing metadata item on the project and create it if necessary if not ( current_project.hasMetadata(self.archive_location_metaId) and current_project.hasMetadata(self.archive_version_metaId) ): # Display user prompt to choose where to archive files res = mari.utils.messageResult( text='This project does not have a location specified for saving ' 'archives to, would you like to create a default one?', title='No archive location found!', buttons=QMessageBox.StandardButton.Ok|QMessageBox.StandardButton.Cancel, icon=QMessageBox.Icon.Information, details='The location that you choose will be saved as additional' 'metadata into the project, so that you only need to do this once.' ) if res == QMessageBox.Ok: mari_user_directory = os.path.abspath( mari.resources.path(mari.resources.USER) ) # Create a default location for saving the archives to default_archive_location = os.path.join( mari_user_directory, 'Archives', current_project.name() ) if not os.path.isdir(default_archive_location): os.makedirs(default_archive_location) self.logger.debug('Default archive location set at: {0}' .format(default_archive_location)) activeWindow = QApplication.activeWindow() # Show prompt for user to choose archive location from archive_location = QFileDialog.getExistingDirectory( parent=activeWindow, caption='Select a location to save the archives', dir=default_archive_location, options=QFileDialog.ShowDirsOnly ) if not archive_location: return # Set base version number archive_version = 0 if os.path.isdir(archive_location): # Set the metadata current_project.setMetadata( self.archive_location_metaId, archive_location) current_project.setMetadata( self.archive_version_metaId, archive_version) else: self.logger.error('### The chosen location: {0} is not a ' 'valid directory!!!' .format(archive_location)) mari.utils.message( text='{0}\nis not a valid directory!'.format(archive_location), title='Invalid directory!', icon=QMessageBox.Icon.Critical ) return IOError else: self.logger.debug('User cancelled operation, aborting!') return # Archive the project to the location defined # in metadata and increment version number archive_location = current_project.metadata(self.archive_location_metaId) archive_version = str( int(current_project.metadata(self.archive_version_metaId)) + 1 ) # Format location to save the archive to archive_location_dir = os.path.join( archive_location, 'v'+archive_version.zfill(self.version_padding) ) archive_location_path = os.path.join( archive_location_dir, current_project.name()+'.mra' ) # Create location to save to if not os.path.isdir(archive_location_dir): self.logger.debug('Directories being created for location ' 'since they do not already exist...') os.makedirs(archive_location_dir) self.logger.debug('Attempting to archive project at: {0}' .format(archive_location_path)) # Clear the project history and try: mari.history.clear(False) except RuntimeError: self.logger.error('### Could not clear the history because no project was open,' 'or the current project requires saving!!!\n{0}' .format(traceback.print_exc())) mari.utils.message( text='Cannot archive the project! Ran into an issue while trying to clear' 'the project history!', title='Runtime error!', icon=QMessageBox.Icon.Critical, details=traceback.print_exc() ) return # perform memory garbage collection mari.ddi.garbageCollect() mari.ddi.clearMemoryCache() self.logger.debug('Saving project...') # Save the project first current_project.save() # Close current project before archiving for successful operation # Note: explicitly using ``confirm_if_modified flag`` in API fails current_project.close(False) try: mari.projects.archive(project_uuid, archive_location_path) self.logger.info('Successfully archived project!') except RuntimeError: self.logger.error('### User cancelled the operation/Project was ' 'open while attempting to archive!!!' .format(traceback.print_exc())) mari.utils.message( text='Cannot archive the project! Is it still open?', title='Runtime error!', icon=QMessageBox.Icon.Critical ) raise RuntimeError except ValueError: self.logger.error('### Invalid project specified for archiving!!!' .format(traceback.print_exc())) mari.utils.message( text='Invalid project was specified for archiving!', title='Invalid project!', icon=QMessageBox.Icon.Critical ) raise ValueError except IOError: self.logger.error('### Error occurred while writing archive to disk!!!' .format(traceback.print_exc())) mari.utils.message( text='Error occurred while trying to write the archive to disk!', title='IO Error!', icon=QMessageBox.Icon.Critical, details=traceback.print_exc() ) raise IOError # Re-open project after successful archive mari.projects.open(project_uuid) self.logger.info('Incrementing current version of project...') # Update metadata for the version of the project mari.projects.current().setMetadata( self.archive_version_metaId, archive_version ) # Save project again to store metadata changes mari.projects.save() self.logger.info('Successfully performed incremental archive save operation!')