''' Created on Nov 20, 2017 @author: Charlie McLouth ''' from shutil import rmtree as shutil_rmtree from os import access as os_access, chmod as os_chmod, W_OK as os_W_OK, \ environ as osenviron, makedirs as osmakedirs, stat as osstat, \ remove as osremovefile, listdir as oslistdir from tempfile import mkdtemp from stat import S_IWUSR as stat_S_IWUSR from p4rest.p4 import P4, P4Exception from datetime import datetime, timedelta from flask import json import logging logger = logging.getLogger(__name__) APP_NAME = "p4rest" APP_CONFIG_KEY = APP_NAME.upper() + "_CONFIG" JSON_DATETIME_FMT = "%Y-%m-%dT%H:%M:%S.%fZ" def rmtree(path, ignore_errors=False, onerror=None): def roerror(func, path, exc_info): """ Error handler for ``shutil.rmtree``. lifted from StackOverflow.com If the error is due to an access error (read only file) it attempts to add write permission and then retries. If the error is for another reason it re-raises the error. Usage : ``shutil.rmtree(path, onerror=onerror)`` """ if not os_access(path, os_W_OK): # Is the error an access error ? os_chmod(path, stat_S_IWUSR) func(path) elif onerror is not None: onerror(func, path, exc_info) else: raise return shutil_rmtree(path, ignore_errors, roerror) class P4JSONEncoder(json.JSONEncoder): ''' Extending the encoder Additional object handlers can be added by creating a method named: default_ ''' def default(self, o): # default only gets called for complex types. Does not get called for standard types # such as: int, str, list, dict, tuple, etc if hasattr(o, "__class__"): classobj = getattr(o, "__class__") classname = classobj.__name__ # check to have if we have a handler for the class if classname is not None: funcName = "default_{}".format(classobj.__name__) func = getattr(self, funcName, None) if func is not None: return func(o) if isinstance(o, Exception): error = {} classobj = getattr(o, "__class__") error["type"] = classobj.__name__ if isinstance(o, AttributeError): error["message"] = "Unknown Attribute: '{}'.".format(o.args[0]) else: error["message"] = str(o) return error return json.JSONEncoder.default(self, o) def default_datetime(self, o): '''converts datetime object to a str''' #2015-10-26T07:46:36.611Z return o.strftime(JSON_DATETIME_FMT) def default_timedelta(self, o): '''converts timedelta object to a str''' return str(o) def default_DepotFile(self, o): '''converts DepotFile object to a dict''' depotFile = {"depotFile": o.depotFile, "revisions": o.revisions} return depotFile def default_Revision(self, o): '''converts Revision object to a dict''' revision = {"depotFile": o.depotFile, "rev": o.rev, "change": o.change, "action": o.action, "type": o.type, "time": o.time, "user": o.user, "client": o.client, "desc": o.desc, "digest": o.digest, "fileSize": o.fileSize} if len(o.integrations) > 0: revision['integrations'] = o.integrations return revision def default_Integration(self, o): '''converts Integration object to a dict''' integration = {"how": o.how, "file": o.file, "srev": o.srev, "erev": o.erev} return integration def default_P4Exception(self, o): '''converts P4Exception object to a dict''' error = {} classobj = getattr(o, "__class__") error["type"] = classobj.__name__ error["message"] = getattr(o, "errors") return error