'''
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_<classname>
'''
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