2018-09-21 08:34:55 +00:00
|
|
|
from __future__ import print_function
|
2019-11-28 11:25:52 +00:00
|
|
|
import os.path
|
2017-11-08 04:27:57 +00:00
|
|
|
import sys
|
|
|
|
|
|
|
|
|
|
|
|
_COLOR_CODES = {
|
2018-09-26 06:09:00 +00:00
|
|
|
"white": u'\033[0m',
|
|
|
|
"red": u'\033[31m',
|
|
|
|
"green": u'\033[32m',
|
|
|
|
"orange": u'\033[33m',
|
|
|
|
"blue": u'\033[34m',
|
|
|
|
"purple": u'\033[35m',
|
|
|
|
"W": u'\033[0m',
|
|
|
|
"R": u'\033[31m',
|
|
|
|
"G": u'\033[32m',
|
|
|
|
"O": u'\033[33m',
|
|
|
|
"B": u'\033[34m',
|
|
|
|
"P": u'\033[35m'
|
2017-11-08 04:27:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-09-21 08:34:55 +00:00
|
|
|
def console_log(data, color="white", end="\n"):
|
2017-11-08 04:27:57 +00:00
|
|
|
"""
|
|
|
|
log data to console.
|
|
|
|
(if not flush console log, Gitlab-CI won't update logs during job execution)
|
|
|
|
|
|
|
|
:param data: data content
|
|
|
|
:param color: color
|
|
|
|
"""
|
|
|
|
if color not in _COLOR_CODES:
|
|
|
|
color = "white"
|
|
|
|
color_codes = _COLOR_CODES[color]
|
2018-12-04 12:46:48 +00:00
|
|
|
if isinstance(data, type(b'')):
|
2018-09-26 06:09:00 +00:00
|
|
|
data = data.decode('utf-8', 'replace')
|
2018-09-21 08:34:55 +00:00
|
|
|
print(color_codes + data, end=end)
|
2017-11-08 04:27:57 +00:00
|
|
|
if color not in ["white", "W"]:
|
|
|
|
# reset color to white for later logs
|
2018-09-26 06:09:00 +00:00
|
|
|
print(_COLOR_CODES["white"] + u"\r")
|
2018-09-21 08:34:55 +00:00
|
|
|
sys.stdout.flush()
|
2018-12-14 16:37:43 +00:00
|
|
|
|
|
|
|
|
2019-11-22 07:49:40 +00:00
|
|
|
__LOADED_MODULES = dict()
|
|
|
|
# we should only load one module once.
|
|
|
|
# if we load one module twice,
|
|
|
|
# python will regard the same object loaded in the first time and second time as different objects.
|
|
|
|
# it will lead to strange errors like `isinstance(object, type_of_this_object)` return False
|
|
|
|
|
|
|
|
|
2019-11-28 11:25:52 +00:00
|
|
|
def load_source(path):
|
|
|
|
"""
|
|
|
|
Dynamic loading python file. Note that this function SHOULD NOT be used to replace ``import``.
|
|
|
|
It should only be used when the package path is only available in runtime.
|
|
|
|
|
|
|
|
:param path: The path of python file
|
|
|
|
:return: Loaded object
|
|
|
|
"""
|
|
|
|
path = os.path.realpath(path)
|
|
|
|
# load name need to be unique, otherwise it will update the already loaded module
|
|
|
|
load_name = str(len(__LOADED_MODULES))
|
2018-12-14 16:37:43 +00:00
|
|
|
try:
|
2019-11-28 11:25:52 +00:00
|
|
|
return __LOADED_MODULES[path]
|
2019-11-22 07:49:40 +00:00
|
|
|
except KeyError:
|
|
|
|
try:
|
|
|
|
from importlib.machinery import SourceFileLoader
|
2019-11-28 11:25:52 +00:00
|
|
|
ret = SourceFileLoader(load_name, path).load_module()
|
2019-11-22 07:49:40 +00:00
|
|
|
except ImportError:
|
|
|
|
# importlib.machinery doesn't exists in Python 2 so we will use imp (deprecated in Python 3)
|
|
|
|
import imp
|
2019-11-28 11:25:52 +00:00
|
|
|
ret = imp.load_source(load_name, path)
|
|
|
|
__LOADED_MODULES[path] = ret
|
2019-11-22 07:49:40 +00:00
|
|
|
return ret
|