maya-umbrella 0.3.0__py2.py3-none-any.whl → 0.4.1__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of maya-umbrella might be problematic. Click here for more details.
- maya_umbrella/__init__.py +2 -2
- maya_umbrella/__version__.py +1 -1
- maya_umbrella/constants.py +5 -0
- maya_umbrella/core.py +83 -42
- maya_umbrella/filesystem.py +35 -2
- maya_umbrella/hooks/delete_turtle.py +7 -2
- maya_umbrella/hooks/delete_unknown_plugin_node.py +8 -7
- maya_umbrella/hooks/fix_model_panel.py +2 -3
- maya_umbrella/hooks/fix_on_model_change_3dc.py +11 -6
- maya_umbrella/log.py +37 -0
- maya_umbrella/vaccine.py +169 -27
- maya_umbrella/vaccines/vaccine1.py +10 -12
- maya_umbrella/vaccines/vaccine2.py +28 -33
- maya_umbrella/vaccines/vaccine3.py +33 -65
- maya_umbrella-0.4.1.dist-info/METADATA +138 -0
- maya_umbrella-0.4.1.dist-info/RECORD +20 -0
- maya_umbrella-0.3.0.dist-info/METADATA +0 -85
- maya_umbrella-0.3.0.dist-info/RECORD +0 -18
- {maya_umbrella-0.3.0.dist-info → maya_umbrella-0.4.1.dist-info}/LICENSE +0 -0
- {maya_umbrella-0.3.0.dist-info → maya_umbrella-0.4.1.dist-info}/WHEEL +0 -0
maya_umbrella/__init__.py
CHANGED
maya_umbrella/__version__.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "0.
|
|
1
|
+
__version__ = "0.4.1"
|
maya_umbrella/core.py
CHANGED
|
@@ -1,76 +1,117 @@
|
|
|
1
1
|
# Import built-in modules
|
|
2
2
|
import logging
|
|
3
|
-
import re
|
|
4
3
|
|
|
5
4
|
# Import third-party modules
|
|
6
5
|
import maya.api.OpenMaya as om
|
|
6
|
+
import maya.cmds as cmds
|
|
7
7
|
|
|
8
8
|
# Import local modules
|
|
9
9
|
from maya_umbrella.filesystem import get_hooks
|
|
10
10
|
from maya_umbrella.filesystem import get_vaccines
|
|
11
11
|
from maya_umbrella.filesystem import load_hook
|
|
12
|
+
from maya_umbrella.log import setup_logger
|
|
13
|
+
from maya_umbrella.vaccine import MayaVirusCleaner
|
|
12
14
|
|
|
13
15
|
|
|
14
|
-
class
|
|
16
|
+
class MayaVirusDefender(object):
|
|
15
17
|
callback_ids = []
|
|
16
18
|
remove_callbacks = []
|
|
17
19
|
_bad_files = []
|
|
18
20
|
_vaccines = []
|
|
19
21
|
callback_maps = {
|
|
20
|
-
"
|
|
21
|
-
"
|
|
22
|
-
"
|
|
23
|
-
"
|
|
24
|
-
"
|
|
25
|
-
"
|
|
26
|
-
"
|
|
27
|
-
"
|
|
28
|
-
"
|
|
22
|
+
"after_open": om.MSceneMessage.kAfterOpen,
|
|
23
|
+
"maya_initialized": om.MSceneMessage.kMayaInitialized,
|
|
24
|
+
"after_import": om.MSceneMessage.kAfterImport,
|
|
25
|
+
"after_import_reference": om.MSceneMessage.kAfterImportReference,
|
|
26
|
+
"after_load_reference": om.MSceneMessage.kAfterLoadReference,
|
|
27
|
+
"before_save": om.MSceneMessage.kBeforeSave,
|
|
28
|
+
"before_import": om.MSceneMessage.kBeforeImport,
|
|
29
|
+
"before_load_reference": om.MSceneMessage.kBeforeLoadReference,
|
|
30
|
+
"before_import_reference": om.MSceneMessage.kBeforeImportReference,
|
|
31
|
+
"maya_exiting": om.MSceneMessage.kMayaExiting,
|
|
29
32
|
}
|
|
30
33
|
|
|
31
|
-
def __init__(self):
|
|
32
|
-
|
|
34
|
+
def __init__(self, auto_fix=True):
|
|
35
|
+
"""Initialize the MayaVirusDefender.
|
|
36
|
+
|
|
37
|
+
Args:
|
|
38
|
+
auto_fix (bool): Whether to automatically fix issues.
|
|
39
|
+
"""
|
|
40
|
+
logger = logging.getLogger(__name__)
|
|
41
|
+
self.auto_fix = auto_fix
|
|
42
|
+
self.logger = setup_logger(logger)
|
|
43
|
+
self.virus_cleaner = MayaVirusCleaner(self.logger)
|
|
33
44
|
self.load_vaccines()
|
|
34
45
|
|
|
35
46
|
def load_vaccines(self):
|
|
47
|
+
"""Load all vaccines."""
|
|
36
48
|
for vaccine in get_vaccines():
|
|
37
|
-
|
|
49
|
+
vaccine_class = load_hook(vaccine).Vaccine
|
|
50
|
+
try:
|
|
51
|
+
self._vaccines.append(vaccine_class(api=self.virus_cleaner, logger=self.logger))
|
|
52
|
+
except Exception as e:
|
|
53
|
+
self.logger.error("Error loading vaccine: %s", e)
|
|
38
54
|
|
|
39
55
|
@property
|
|
40
56
|
def vaccines(self):
|
|
57
|
+
"""Get all loaded vaccines.
|
|
58
|
+
|
|
59
|
+
Returns:
|
|
60
|
+
list: A list of loaded vaccines.
|
|
61
|
+
"""
|
|
41
62
|
return self._vaccines
|
|
42
63
|
|
|
43
64
|
def run_hooks(self):
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
65
|
+
"""Run all hooks, only works in non-batch mode."""
|
|
66
|
+
if not cmds.about(batch=True):
|
|
67
|
+
for hook_file in get_hooks():
|
|
68
|
+
self.logger.debug("run_hook: %s", hook_file)
|
|
69
|
+
try:
|
|
70
|
+
load_hook(hook_file).hook(virus_cleaner=self.virus_cleaner)
|
|
71
|
+
except Exception as e:
|
|
72
|
+
self.logger.error("Error running hook: %s", e)
|
|
47
73
|
|
|
48
|
-
def
|
|
49
|
-
|
|
50
|
-
matched = re.search(r"(?P<name>(after|before))", name)
|
|
51
|
-
if matched:
|
|
52
|
-
method_name = matched.group("name")
|
|
53
|
-
self.logger.info("setup %s.", name)
|
|
54
|
-
self.callback_ids.append(
|
|
55
|
-
{name: om.MSceneMessage.addCallback(callback, getattr(self, "{0}_callback".format(method_name)))}
|
|
56
|
-
)
|
|
57
|
-
|
|
58
|
-
self.start()
|
|
59
|
-
|
|
60
|
-
def before_callback(self, *args, **kwargs):
|
|
61
|
-
self.logger.info("before_callback.")
|
|
74
|
+
def collect(self):
|
|
75
|
+
"""Collect all issues related to the Maya virus."""
|
|
62
76
|
for vaccine in self.vaccines:
|
|
63
|
-
vaccine.
|
|
64
|
-
self.run_hooks()
|
|
77
|
+
vaccine.collect_issues()
|
|
65
78
|
|
|
66
|
-
def
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
79
|
+
def fix(self):
|
|
80
|
+
"""Fix all issues related to the Maya virus."""
|
|
81
|
+
self.virus_cleaner.fix_all_issues()
|
|
82
|
+
|
|
83
|
+
def report(self):
|
|
84
|
+
"""Report all issues related to the Maya virus."""
|
|
85
|
+
self.virus_cleaner.reset_all_issues()
|
|
86
|
+
self.collect()
|
|
87
|
+
self.virus_cleaner.report_all_issues()
|
|
88
|
+
|
|
89
|
+
def setup(self):
|
|
90
|
+
"""Set up the MayaVirusDefender."""
|
|
91
|
+
self.virus_cleaner.setup_default_callbacks()
|
|
92
|
+
for name, callbacks in self.virus_cleaner.registered_callbacks.items():
|
|
93
|
+
maya_callback = self.callback_maps[name]
|
|
94
|
+
self.logger.debug("%s setup.", name)
|
|
95
|
+
for func in callbacks:
|
|
96
|
+
self.callback_ids.append(om.MSceneMessage.addCallback(maya_callback, func))
|
|
97
|
+
for name, callbacks in self.callback_maps.items():
|
|
98
|
+
self.logger.debug("setup callback %s.", name)
|
|
99
|
+
self.callback_ids.append(om.MSceneMessage.addCallback(callbacks, self._callback))
|
|
100
|
+
|
|
101
|
+
def _callback(self, *args, **kwargs):
|
|
102
|
+
"""Callback function for MayaVirusDefender.
|
|
103
|
+
|
|
104
|
+
Args:
|
|
105
|
+
*args: Variable length argument list.
|
|
106
|
+
**kwargs: Arbitrary keyword arguments.
|
|
107
|
+
"""
|
|
108
|
+
if self.auto_fix:
|
|
109
|
+
self.collect()
|
|
110
|
+
self.fix()
|
|
111
|
+
self.run_hooks()
|
|
112
|
+
else:
|
|
113
|
+
self.report()
|
|
71
114
|
|
|
72
115
|
def start(self):
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
vaccine.process()
|
|
76
|
-
self.run_hooks()
|
|
116
|
+
"""Start the MayaVirusDefender."""
|
|
117
|
+
self._callback()
|
maya_umbrella/filesystem.py
CHANGED
|
@@ -6,6 +6,10 @@ import os
|
|
|
6
6
|
import random
|
|
7
7
|
import shutil
|
|
8
8
|
import string
|
|
9
|
+
import tempfile
|
|
10
|
+
|
|
11
|
+
# Import local modules
|
|
12
|
+
from maya_umbrella.constants import PACKAGE_NAME
|
|
9
13
|
|
|
10
14
|
|
|
11
15
|
def this_root():
|
|
@@ -17,7 +21,7 @@ def safe_remove_file(file_path):
|
|
|
17
21
|
"""Remove the file at the given path without raising an error if the file does not exist."""
|
|
18
22
|
try:
|
|
19
23
|
os.remove(file_path)
|
|
20
|
-
except
|
|
24
|
+
except OSError:
|
|
21
25
|
pass
|
|
22
26
|
|
|
23
27
|
|
|
@@ -25,7 +29,7 @@ def safe_rmtree(path):
|
|
|
25
29
|
"""Remove the directory at the given path without raising an error if the directory does not exist."""
|
|
26
30
|
try:
|
|
27
31
|
shutil.rmtree(path)
|
|
28
|
-
except
|
|
32
|
+
except OSError:
|
|
29
33
|
pass
|
|
30
34
|
|
|
31
35
|
|
|
@@ -106,5 +110,34 @@ def get_hooks():
|
|
|
106
110
|
|
|
107
111
|
|
|
108
112
|
def get_vaccines():
|
|
113
|
+
"""Get a list of all vaccine files.
|
|
114
|
+
|
|
115
|
+
Returns:
|
|
116
|
+
list: A list of vaccine files.
|
|
117
|
+
"""
|
|
109
118
|
pattern = os.path.join(this_root(), "vaccines", "*.py")
|
|
110
119
|
return [vaccine for vaccine in glob.glob(pattern) if "__init__" not in vaccine]
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def get_log_root():
|
|
123
|
+
"""Get the log root directory.
|
|
124
|
+
|
|
125
|
+
Returns:
|
|
126
|
+
str: The log root directory.
|
|
127
|
+
"""
|
|
128
|
+
return os.getenv("MAYA_UMBRELLA_LOG_ROOT", tempfile.gettempdir())
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def get_log_file():
|
|
132
|
+
"""Get the path of the log file.
|
|
133
|
+
|
|
134
|
+
Returns:
|
|
135
|
+
str: The path of the log file.
|
|
136
|
+
"""
|
|
137
|
+
root = get_log_root()
|
|
138
|
+
try:
|
|
139
|
+
os.makedirs(root)
|
|
140
|
+
except OSError:
|
|
141
|
+
pass
|
|
142
|
+
name = os.getenv("MAYA_UMBRELLA_LOG_NAME", PACKAGE_NAME)
|
|
143
|
+
return os.path.join(root, "{name}.log".format(name=name))
|
|
@@ -3,11 +3,16 @@ import maya.cmds as cmds
|
|
|
3
3
|
import maya.mel as mel
|
|
4
4
|
|
|
5
5
|
|
|
6
|
-
def hook(
|
|
6
|
+
def hook(virus_cleaner):
|
|
7
7
|
for plugin in ["Turtle.mll", "mayatomr.mll"]:
|
|
8
8
|
if cmds.pluginInfo(plugin, q=1, loaded=1):
|
|
9
9
|
cmds.unloadPlugin(plugin, f=1)
|
|
10
|
-
turtle_nodes = [
|
|
10
|
+
turtle_nodes = [
|
|
11
|
+
"TurtleRenderOptions",
|
|
12
|
+
"TurtleUIOptions",
|
|
13
|
+
"TurtleBakeLayerManager",
|
|
14
|
+
"TurtleDefaultBakeLayer",
|
|
15
|
+
]
|
|
11
16
|
for node in turtle_nodes:
|
|
12
17
|
if cmds.objExists(node):
|
|
13
18
|
cmds.lockNode(node, lock=1)
|
|
@@ -2,28 +2,29 @@
|
|
|
2
2
|
import maya.cmds as cmds
|
|
3
3
|
|
|
4
4
|
|
|
5
|
-
def hook(
|
|
5
|
+
def hook(virus_cleaner):
|
|
6
6
|
unknown_node = cmds.ls(type="unknown")
|
|
7
7
|
unknown_plugin = cmds.unknownPlugin(query=True, l=True)
|
|
8
8
|
if unknown_node:
|
|
9
9
|
for nodeObj in unknown_node:
|
|
10
10
|
if cmds.objExists(nodeObj):
|
|
11
11
|
if cmds.referenceQuery(nodeObj, isNodeReferenced=True):
|
|
12
|
-
logger.warning("Node from reference, skip.
|
|
12
|
+
virus_cleaner.logger.warning("Node from reference, skip. {}".format(nodeObj))
|
|
13
13
|
continue
|
|
14
14
|
if cmds.lockNode(nodeObj, query=True)[0]:
|
|
15
15
|
try:
|
|
16
16
|
cmds.lockNode(nodeObj, lock=False)
|
|
17
|
-
except Exception
|
|
18
|
-
logger.warning(
|
|
17
|
+
except Exception:
|
|
18
|
+
virus_cleaner.logger.warning(
|
|
19
|
+
"The node is locked and cannot be unlocked. skip {}".format(nodeObj))
|
|
19
20
|
continue
|
|
20
21
|
try:
|
|
21
22
|
cmds.delete(nodeObj)
|
|
22
|
-
logger.warning("Delete node
|
|
23
|
-
except Exception
|
|
23
|
+
virus_cleaner.logger.warning("Delete node: {}".format(nodeObj))
|
|
24
|
+
except Exception:
|
|
24
25
|
pass
|
|
25
26
|
|
|
26
27
|
if unknown_plugin:
|
|
27
28
|
for plugObj in unknown_plugin:
|
|
28
29
|
cmds.unknownPlugin(plugObj, remove=True)
|
|
29
|
-
logger.warning("Delete plug-in
|
|
30
|
+
virus_cleaner.logger.warning("Delete plug-in: {}".format(plugObj))
|
|
@@ -2,13 +2,12 @@
|
|
|
2
2
|
import maya.cmds as cmds
|
|
3
3
|
|
|
4
4
|
|
|
5
|
-
def hook(
|
|
5
|
+
def hook(virus_cleaner):
|
|
6
6
|
for model_panel in cmds.getPanel(typ="modelPanel"):
|
|
7
|
-
|
|
8
7
|
# Get callback of the model editor
|
|
9
8
|
callback = cmds.modelEditor(model_panel, query=True, editorChanged=True)
|
|
10
9
|
|
|
11
10
|
# If the callback is the erroneous `CgAbBlastPanelOptChangeCallback`
|
|
12
11
|
if callback == "CgAbBlastPanelOptChangeCallback":
|
|
13
|
-
|
|
12
|
+
virus_cleaner.logger.info("Remove the callbacks from the editor")
|
|
14
13
|
cmds.modelEditor(model_panel, edit=True, editorChanged="")
|
|
@@ -3,12 +3,17 @@ import maya.cmds as cmds
|
|
|
3
3
|
import maya.mel as mel
|
|
4
4
|
|
|
5
5
|
|
|
6
|
-
def hook(
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
def hook(virus_cleaner):
|
|
7
|
+
try:
|
|
8
|
+
mel.eval("global proc onModelChange3dc(string $a){}")
|
|
9
|
+
except Exception:
|
|
10
|
+
pass
|
|
9
11
|
try:
|
|
10
12
|
cmds.delete("fixCgAbBlastPanelOptChangeCallback")
|
|
11
|
-
except:
|
|
13
|
+
except Exception:
|
|
14
|
+
pass
|
|
15
|
+
try:
|
|
16
|
+
script = "global proc CgAbBlastPanelOptChangeCallback(string $i){}"
|
|
17
|
+
mel.eval(script)
|
|
18
|
+
except Exception:
|
|
12
19
|
pass
|
|
13
|
-
script = "global proc CgAbBlastPanelOptChangeCallback(string $i){}"
|
|
14
|
-
mel.eval(script)
|
maya_umbrella/log.py
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Import built-in modules
|
|
2
|
+
import logging.handlers
|
|
3
|
+
import os
|
|
4
|
+
|
|
5
|
+
# Import local modules
|
|
6
|
+
from maya_umbrella.constants import LOG_FORMAT
|
|
7
|
+
from maya_umbrella.constants import LOG_MAX_BYTES
|
|
8
|
+
from maya_umbrella.constants import PACKAGE_NAME
|
|
9
|
+
from maya_umbrella.filesystem import get_log_file
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def setup_logger(logger=None, logfile=None, log_level=None):
|
|
13
|
+
"""Set up the logger with the specified log file and log level.
|
|
14
|
+
|
|
15
|
+
Args:
|
|
16
|
+
logger (logging.Logger, optional): The logger to set up. Defaults to the logger for the package.
|
|
17
|
+
logfile (str, optional): The path to the log file. Defaults to the log file returned by `get_log_file()`.
|
|
18
|
+
log_level (int, optional): The log level. Defaults to `logging.INFO`.
|
|
19
|
+
|
|
20
|
+
Returns:
|
|
21
|
+
logging.Logger: The set up logger.
|
|
22
|
+
"""
|
|
23
|
+
logger = logger or logging.getLogger(PACKAGE_NAME)
|
|
24
|
+
log_level = log_level or os.getenv("MAYA_UMBRELLA_LOG_LEVEL", "INFO")
|
|
25
|
+
logger.setLevel(log_level)
|
|
26
|
+
logfile = logfile or get_log_file()
|
|
27
|
+
if not len(logger.handlers):
|
|
28
|
+
filehandler = logging.handlers.RotatingFileHandler(
|
|
29
|
+
logfile,
|
|
30
|
+
mode="a",
|
|
31
|
+
backupCount=7,
|
|
32
|
+
delay=True,
|
|
33
|
+
maxBytes=LOG_MAX_BYTES,
|
|
34
|
+
)
|
|
35
|
+
filehandler.setFormatter(logging.Formatter(LOG_FORMAT))
|
|
36
|
+
logger.addHandler(filehandler)
|
|
37
|
+
return logger
|
maya_umbrella/vaccine.py
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
# Import built-in modules
|
|
2
|
+
from collections import defaultdict
|
|
2
3
|
import glob
|
|
3
4
|
import logging
|
|
4
5
|
import os
|
|
@@ -11,70 +12,211 @@ from maya_umbrella.filesystem import safe_remove_file
|
|
|
11
12
|
from maya_umbrella.filesystem import safe_rmtree
|
|
12
13
|
|
|
13
14
|
|
|
14
|
-
class
|
|
15
|
-
virus_name = None
|
|
16
|
-
|
|
15
|
+
class MayaVirusCleaner(object):
|
|
17
16
|
_bad_files = []
|
|
17
|
+
_bad_nodes = []
|
|
18
|
+
_bad_script_nodes = []
|
|
19
|
+
_bad_script_jobs = []
|
|
20
|
+
_registered_callbacks = defaultdict(list)
|
|
21
|
+
_fix_funcs = []
|
|
18
22
|
|
|
19
|
-
def __init__(self, logger=None):
|
|
20
|
-
self.
|
|
23
|
+
def __init__(self, logger=None, auto_fix=True):
|
|
24
|
+
self.logger = logger or logging.getLogger(__name__)
|
|
25
|
+
self.auto_fix = auto_fix
|
|
21
26
|
|
|
22
27
|
@property
|
|
23
28
|
def user_app_dir(self):
|
|
29
|
+
"""Return the user application directory."""
|
|
24
30
|
return cmds.internalVar(userAppDir=True)
|
|
25
31
|
|
|
32
|
+
@property
|
|
33
|
+
def maya_file(self):
|
|
34
|
+
"""Return the current Maya file."""
|
|
35
|
+
return cmds.file(q=True, sn=True)
|
|
36
|
+
|
|
26
37
|
@property
|
|
27
38
|
def maya_install_root(self):
|
|
39
|
+
"""Return the Maya installation root directory."""
|
|
28
40
|
return os.environ["MAYA_LOCATION"]
|
|
29
41
|
|
|
30
42
|
@property
|
|
31
43
|
def user_script_path(self):
|
|
44
|
+
"""Return the user script directory."""
|
|
32
45
|
return cmds.internalVar(userScriptDir=True)
|
|
33
46
|
|
|
34
47
|
@property
|
|
35
48
|
def local_script_path(self):
|
|
49
|
+
"""Return the local script directory."""
|
|
36
50
|
return os.path.join(self.user_app_dir, "scripts")
|
|
37
51
|
|
|
38
52
|
@property
|
|
39
53
|
def bad_files(self):
|
|
40
|
-
|
|
54
|
+
"""Return a list of bad files."""
|
|
55
|
+
return [path for path in list(set(self._bad_files)) if os.path.exists(path)]
|
|
41
56
|
|
|
42
57
|
@property
|
|
43
58
|
def bad_nodes(self):
|
|
44
|
-
|
|
59
|
+
"""Return a list of bad nodes."""
|
|
60
|
+
return list(set(self._bad_nodes))
|
|
45
61
|
|
|
46
62
|
@property
|
|
47
63
|
def bad_script_nodes(self):
|
|
48
|
-
|
|
64
|
+
"""Return a list of bad script nodes."""
|
|
65
|
+
return list(set(self._bad_script_nodes))
|
|
66
|
+
|
|
67
|
+
@property
|
|
68
|
+
def bad_script_jobs(self):
|
|
69
|
+
"""Return a list of bad script jobs."""
|
|
70
|
+
return list(set(self._bad_script_jobs))
|
|
71
|
+
|
|
72
|
+
def callback_remove_rename_temp_files(self, *args, **kwargs):
|
|
73
|
+
"""
|
|
74
|
+
Remove temporary files in the local script path.
|
|
75
|
+
"""
|
|
76
|
+
self.logger.info("Removing temporary files in %s", self.local_script_path)
|
|
77
|
+
[safe_remove_file(temp_file) for temp_file in glob.glob(os.path.join(self.local_script_path, "._*"))]
|
|
78
|
+
|
|
79
|
+
@property
|
|
80
|
+
def registered_callbacks(self):
|
|
81
|
+
return self._registered_callbacks
|
|
82
|
+
|
|
83
|
+
def add_bad_files(self, files):
|
|
84
|
+
self._bad_files.extend(files)
|
|
85
|
+
|
|
86
|
+
def add_bad_file(self, file):
|
|
87
|
+
self._bad_files.append(file)
|
|
88
|
+
|
|
89
|
+
def add_bad_nodes(self, nodes):
|
|
90
|
+
self._bad_nodes.extend(nodes)
|
|
91
|
+
|
|
92
|
+
def add_bad_node(self, node):
|
|
93
|
+
self._bad_nodes.append(node)
|
|
94
|
+
|
|
95
|
+
def add_bad_script_jobs(self, jobs):
|
|
96
|
+
self._bad_script_jobs.extend(jobs)
|
|
97
|
+
|
|
98
|
+
def add_bad_script_job(self, job):
|
|
99
|
+
self._bad_script_jobs.append(job)
|
|
100
|
+
|
|
101
|
+
def add_bad_script_nodes(self, nodes):
|
|
102
|
+
self._bad_script_nodes.extend(nodes)
|
|
103
|
+
|
|
104
|
+
def add_bad_script_node(self, node):
|
|
105
|
+
self._bad_script_nodes.append(node)
|
|
49
106
|
|
|
50
|
-
def
|
|
51
|
-
|
|
107
|
+
def register_callback(self, callback_name, callback):
|
|
108
|
+
"""Register a callback to be executed before or after processing."""
|
|
109
|
+
self._registered_callbacks[callback_name].append(callback)
|
|
52
110
|
|
|
53
|
-
def
|
|
54
|
-
self.
|
|
111
|
+
def add_after_open_callback(self, callback):
|
|
112
|
+
self.register_callback("after_open", callback)
|
|
113
|
+
|
|
114
|
+
def add_maya_initialized_callback(self, callback):
|
|
115
|
+
self.register_callback("maya_initialized", callback)
|
|
116
|
+
|
|
117
|
+
def add_after_import_callback(self, callback):
|
|
118
|
+
self.register_callback("after_import", callback)
|
|
119
|
+
|
|
120
|
+
def add_after_import_reference_callback(self, callback):
|
|
121
|
+
self.register_callback("after_import_reference", callback)
|
|
122
|
+
|
|
123
|
+
def add_after_load_reference_callback(self, callback):
|
|
124
|
+
self.register_callback("after_load_reference", callback)
|
|
125
|
+
|
|
126
|
+
def add_before_save_callback(self, callback):
|
|
127
|
+
self.register_callback("before_save", callback)
|
|
128
|
+
|
|
129
|
+
def add_before_import_callback(self, callback):
|
|
130
|
+
self.register_callback("before_import", callback)
|
|
131
|
+
|
|
132
|
+
def add_before_load_reference_callback(self, callback):
|
|
133
|
+
self.register_callback("before_load_reference", callback)
|
|
134
|
+
|
|
135
|
+
def add_before_import_reference_callback(self, callback):
|
|
136
|
+
self.register_callback("before_import_reference", callback)
|
|
137
|
+
|
|
138
|
+
def add_maya_exiting_callback(self, callback):
|
|
139
|
+
self.register_callback("maya_exiting", callback)
|
|
140
|
+
|
|
141
|
+
def setup_default_callbacks(self):
|
|
142
|
+
self.add_maya_initialized_callback(self.callback_remove_rename_temp_files)
|
|
143
|
+
self.add_maya_exiting_callback(self.callback_remove_rename_temp_files)
|
|
144
|
+
|
|
145
|
+
def add_fix_function(self, func):
|
|
146
|
+
self._fix_funcs.append(func)
|
|
147
|
+
|
|
148
|
+
# fix
|
|
149
|
+
|
|
150
|
+
def fix_script_jobs(self):
|
|
151
|
+
for script_job in self.bad_script_jobs:
|
|
152
|
+
script_num = int(script_job.split(":", 1)[0])
|
|
153
|
+
self.logger.info("Kill script job %s", script_job)
|
|
154
|
+
cmds.scriptJob(kill=script_num, force=True)
|
|
155
|
+
self._bad_script_jobs.remove(script_job)
|
|
156
|
+
|
|
157
|
+
def fix_bad_files(self):
|
|
55
158
|
for file_ in self.bad_files:
|
|
56
159
|
if os.path.exists(file_):
|
|
57
160
|
if os.path.isfile(file_):
|
|
58
|
-
self.
|
|
161
|
+
self.logger.info("Removing %s", file_)
|
|
59
162
|
safe_remove_file(file_)
|
|
163
|
+
self._bad_files.remove(file_)
|
|
60
164
|
else:
|
|
61
|
-
self.
|
|
165
|
+
self.logger.info("Removing folder %s", file_)
|
|
62
166
|
safe_rmtree(file_)
|
|
167
|
+
self._bad_files.remove(file_)
|
|
63
168
|
|
|
64
|
-
def
|
|
169
|
+
def fix_bad_nodes(self):
|
|
65
170
|
for node in self.bad_nodes:
|
|
66
|
-
self.
|
|
67
|
-
|
|
68
|
-
|
|
171
|
+
self.logger.info("Deleting %s", node)
|
|
172
|
+
try:
|
|
173
|
+
cmds.lockNode(node, lock=False)
|
|
174
|
+
except ValueError:
|
|
175
|
+
pass
|
|
176
|
+
try:
|
|
177
|
+
cmds.delete(node)
|
|
178
|
+
except ValueError:
|
|
179
|
+
pass
|
|
180
|
+
self._bad_nodes.remove(node)
|
|
181
|
+
|
|
182
|
+
def fix_all_issues(self):
|
|
183
|
+
"""Fix all issues related to the Maya virus."""
|
|
184
|
+
self.fix_bad_files()
|
|
185
|
+
self.fix_bad_nodes()
|
|
186
|
+
self.fix_script_jobs()
|
|
187
|
+
for func in self._fix_funcs:
|
|
188
|
+
func()
|
|
189
|
+
|
|
190
|
+
def report_all_issues(self):
|
|
191
|
+
"""Report all issues related to the Maya virus."""
|
|
192
|
+
self.logger.info("Bad files: %s", self.bad_files)
|
|
193
|
+
self.logger.info("Bad nodes: %s", self.bad_nodes)
|
|
194
|
+
self.logger.info("Bad script jobs: %s", self.bad_script_jobs)
|
|
195
|
+
|
|
196
|
+
def reset_all_issues(self):
|
|
197
|
+
"""Reset all issues related to the Maya virus."""
|
|
198
|
+
self._bad_files = []
|
|
199
|
+
self._bad_nodes = []
|
|
200
|
+
self._bad_script_nodes = []
|
|
201
|
+
self._bad_script_jobs = []
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
class AbstractVaccine(object):
|
|
205
|
+
virus_name = None
|
|
206
|
+
|
|
207
|
+
def __init__(self, api, logger):
|
|
208
|
+
"""Abstract class for Vaccine.
|
|
209
|
+
|
|
210
|
+
Args:
|
|
211
|
+
api (MayaVirusCleaner): The VaccineAPI instance.
|
|
212
|
+
logger (Logger): The logger instance.
|
|
69
213
|
|
|
70
|
-
|
|
71
|
-
self.
|
|
72
|
-
self.
|
|
214
|
+
"""
|
|
215
|
+
self.api = api
|
|
216
|
+
self.logger = logger
|
|
73
217
|
|
|
74
|
-
def
|
|
75
|
-
|
|
76
|
-
self.delete_bad_nodes()
|
|
218
|
+
def collect_issues(self):
|
|
219
|
+
raise NotImplementedError
|
|
77
220
|
|
|
78
|
-
def
|
|
79
|
-
self.
|
|
80
|
-
self.after_callback()
|
|
221
|
+
def report_issue(self, name):
|
|
222
|
+
self.logger.warning("%s: Infected by Malware!", name)
|
|
@@ -1,19 +1,17 @@
|
|
|
1
1
|
# Import built-in modules
|
|
2
|
-
import os
|
|
2
|
+
import os
|
|
3
3
|
|
|
4
4
|
# Import local modules
|
|
5
|
-
from maya_umbrella.vaccine import
|
|
5
|
+
from maya_umbrella.vaccine import AbstractVaccine
|
|
6
6
|
|
|
7
7
|
|
|
8
|
-
class Vaccine(
|
|
8
|
+
class Vaccine(AbstractVaccine):
|
|
9
9
|
virus_name = "pu tian tong qi"
|
|
10
10
|
|
|
11
|
-
def
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
os.path.join(self.local_script_path, "fuckVirus.pyc"),
|
|
19
|
-
]
|
|
11
|
+
def collect_issues(self):
|
|
12
|
+
self.api.add_bad_files(
|
|
13
|
+
[
|
|
14
|
+
os.path.join(self.api.local_script_path, "fuckVirus.py"),
|
|
15
|
+
os.path.join(self.api.local_script_path, "fuckVirus.pyc"),
|
|
16
|
+
],
|
|
17
|
+
)
|
|
@@ -7,22 +7,14 @@ import maya.cmds as cmds
|
|
|
7
7
|
# Import local modules
|
|
8
8
|
from maya_umbrella.filesystem import read_file
|
|
9
9
|
from maya_umbrella.filesystem import rename
|
|
10
|
-
from maya_umbrella.vaccine import
|
|
10
|
+
from maya_umbrella.vaccine import AbstractVaccine
|
|
11
11
|
|
|
12
12
|
|
|
13
|
-
class Vaccine(
|
|
13
|
+
class Vaccine(AbstractVaccine):
|
|
14
14
|
virus_name = "zei jian kang"
|
|
15
|
-
_bad_files = []
|
|
16
15
|
|
|
17
|
-
def
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
@property
|
|
21
|
-
def bad_files(self):
|
|
22
|
-
return [os.path.join(self.local_script_path, "vaccine.py"), os.path.join(self.local_script_path, "vaccine.pyc")]
|
|
23
|
-
|
|
24
|
-
def _get_nodes(self):
|
|
25
|
-
bad_script_nodes = []
|
|
16
|
+
def collect_bad_nodes(self):
|
|
17
|
+
"""Collect all bad nodes related to the virus."""
|
|
26
18
|
for script_node in cmds.ls(type="script"):
|
|
27
19
|
if cmds.referenceQuery(script_node, isNodeReferenced=True):
|
|
28
20
|
continue
|
|
@@ -32,34 +24,37 @@ class Vaccine(BaseVaccine):
|
|
|
32
24
|
if not script_string:
|
|
33
25
|
continue
|
|
34
26
|
if "internalVar" in script_string or "userSetup" in script_string or "fuckVirus" in script_string:
|
|
35
|
-
self.
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
27
|
+
self.report_issue(script_node)
|
|
28
|
+
self.api.add_bad_node(script_node)
|
|
29
|
+
|
|
30
|
+
def collect_issues(self):
|
|
31
|
+
"""Collect all issues related to the virus."""
|
|
32
|
+
self.api.add_bad_files(
|
|
33
|
+
[
|
|
34
|
+
os.path.join(self.api.local_script_path, "vaccine.py"),
|
|
35
|
+
os.path.join(self.api.local_script_path, "vaccine.pyc"),
|
|
36
|
+
],
|
|
37
|
+
)
|
|
38
|
+
self.collect_bad_usersetup_py()
|
|
39
|
+
self.collect_bad_nodes()
|
|
40
|
+
|
|
41
|
+
def collect_bad_usersetup_py(self):
|
|
42
|
+
"""Collect all bad userSetup.py files related to the virus."""
|
|
44
43
|
for usersetup_py in [
|
|
45
|
-
os.path.join(self.local_script_path, "vaccine.py"),
|
|
46
|
-
os.path.join(self.user_script_path, "vaccine.py"),
|
|
47
|
-
os.path.join(self.local_script_path, "userSetup.py"),
|
|
48
|
-
os.path.join(self.user_script_path, "userSetup.py"),
|
|
44
|
+
os.path.join(self.api.local_script_path, "vaccine.py"),
|
|
45
|
+
os.path.join(self.api.user_script_path, "vaccine.py"),
|
|
46
|
+
os.path.join(self.api.local_script_path, "userSetup.py"),
|
|
47
|
+
os.path.join(self.api.user_script_path, "userSetup.py"),
|
|
49
48
|
]:
|
|
50
49
|
if os.path.exists(usersetup_py):
|
|
51
50
|
data = read_file(usersetup_py)
|
|
52
51
|
if "petri_dish_path = cmds.internalVar(userAppDir=True) + 'scripts/userSetup.py" in data:
|
|
53
|
-
self.
|
|
54
|
-
self.
|
|
52
|
+
self.report_issue("vaccine.py")
|
|
53
|
+
self.api.add_bad_file(rename(usersetup_py))
|
|
55
54
|
|
|
56
55
|
if (
|
|
57
56
|
"cmds.evalDeferred('leukocyte = vaccine.phage()')" in data
|
|
58
57
|
and "cmds.evalDeferred('leukocyte.occupation()')" in data
|
|
59
58
|
):
|
|
60
|
-
self.
|
|
61
|
-
self.
|
|
62
|
-
|
|
63
|
-
def before_callback(self, *args, **kwargs):
|
|
64
|
-
self.check_usersetup_py()
|
|
65
|
-
super(Vaccine, self).before_callback(args, kwargs)
|
|
59
|
+
self.report_issue("userSetup.py")
|
|
60
|
+
self.api.add_bad_file(rename(usersetup_py))
|
|
@@ -9,65 +9,54 @@ import maya.cmds as cmds
|
|
|
9
9
|
# Import local modules
|
|
10
10
|
from maya_umbrella.filesystem import read_file
|
|
11
11
|
from maya_umbrella.filesystem import rename
|
|
12
|
-
from maya_umbrella.vaccine import
|
|
12
|
+
from maya_umbrella.vaccine import AbstractVaccine
|
|
13
13
|
|
|
14
14
|
|
|
15
|
-
class Vaccine(
|
|
15
|
+
class Vaccine(AbstractVaccine):
|
|
16
16
|
virus_name = "virus2024429"
|
|
17
17
|
hik_regex = r"python\(\"import base64;\s*pyCode\s*=\s*base64\.urlsafe_b64decode\([\'\"].*?[\"\']\);\s*exec\s*\(\s*pyCode\s*\)\"\)\s*;"
|
|
18
|
-
_bad_files = []
|
|
19
18
|
|
|
20
|
-
def
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
@property
|
|
24
|
-
def bad_files(self):
|
|
25
|
-
return self._bad_files
|
|
26
|
-
|
|
27
|
-
@property
|
|
28
|
-
def get_syssst_dir(self):
|
|
29
|
-
return os.path.join(os.getenv("APPDATA"), "syssst")
|
|
30
|
-
|
|
31
|
-
def _get_nodes(self):
|
|
32
|
-
bad_expression = []
|
|
19
|
+
def collect_bad_nodes(self):
|
|
20
|
+
"""Collect all bad nodes related to the virus."""
|
|
33
21
|
for script_node in cmds.ls(type="script"):
|
|
34
22
|
if cmds.referenceQuery(script_node, isNodeReferenced=True):
|
|
35
23
|
continue
|
|
36
24
|
# check uifiguration
|
|
37
25
|
if cmds.objExists("{}.KGMScriptProtector".format(script_node)):
|
|
38
|
-
|
|
26
|
+
self.api.add_bad_node(script_node)
|
|
39
27
|
# check vaccine
|
|
40
28
|
if "_gene" in script_node:
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
return bad_expression
|
|
29
|
+
self.api.add_bad_node(script_node)
|
|
44
30
|
|
|
45
|
-
def
|
|
31
|
+
def collect_bad_mel_files(self):
|
|
32
|
+
"""Collect all bad MEL files related to the virus."""
|
|
46
33
|
# check usersetup.mel
|
|
47
34
|
# C:/Users/hallong/Documents/maya/scripts/usersetup.mel
|
|
48
35
|
# C:/Users/hallong/Documents/maya/xxxx/scripts/usersetup.mel
|
|
49
36
|
for usersetup_mel in [
|
|
50
|
-
os.path.join(self.local_script_path, "usersetup.mel"),
|
|
51
|
-
os.path.join(self.user_script_path, "usersetup.mel"),
|
|
37
|
+
os.path.join(self.api.local_script_path, "usersetup.mel"),
|
|
38
|
+
os.path.join(self.api.user_script_path, "usersetup.mel"),
|
|
52
39
|
]:
|
|
53
40
|
if os.path.exists(usersetup_mel):
|
|
54
41
|
data = read_file(usersetup_mel)
|
|
55
42
|
if "import base64; pyCode = base64.urlsafe_b64decode" in data:
|
|
56
|
-
self.
|
|
43
|
+
self.api.add_bad_file(rename(usersetup_mel))
|
|
57
44
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
45
|
+
def collect_script_jobs(self):
|
|
46
|
+
"""Collect all script jobs related to the virus."""
|
|
47
|
+
virus_gene = [
|
|
48
|
+
"leukocyte",
|
|
49
|
+
"execute",
|
|
50
|
+
]
|
|
61
51
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
self.fix_script_job()
|
|
67
|
-
super(Vaccine, self).before_callback(args, kwargs)
|
|
52
|
+
for script_job in cmds.scriptJob(listJobs=True):
|
|
53
|
+
for virus in virus_gene:
|
|
54
|
+
if virus in script_job:
|
|
55
|
+
self.api.add_bad_script_jobs(script_job)
|
|
68
56
|
|
|
69
|
-
def
|
|
70
|
-
|
|
57
|
+
def fix_bad_hik_files(self):
|
|
58
|
+
"""Fix all bad HIK files related to the virus."""
|
|
59
|
+
pattern = os.path.join(self.api.maya_install_root, "resources/l10n/*/plug-ins/mayaHIK.pres.mel")
|
|
71
60
|
for hik_mel in glob.glob(pattern):
|
|
72
61
|
with open(hik_mel, "rb") as f:
|
|
73
62
|
data = f.read()
|
|
@@ -76,35 +65,14 @@ class Vaccine(BaseVaccine):
|
|
|
76
65
|
except TypeError:
|
|
77
66
|
check = []
|
|
78
67
|
if len(check) > 0:
|
|
68
|
+
self.report_issue(hik_mel)
|
|
79
69
|
with open(hik_mel, "wb") as f:
|
|
80
70
|
f.write(re.sub(self.hik_regex, "", data))
|
|
81
|
-
self.
|
|
82
|
-
|
|
83
|
-
def
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
def get_virus_script_jobs():
|
|
90
|
-
"""Traverse the list of virus script job name.
|
|
91
|
-
Returns:
|
|
92
|
-
list: Malicious virus script job name.
|
|
93
|
-
"""
|
|
94
|
-
return [
|
|
95
|
-
scriptjob
|
|
96
|
-
for scriptjob in cmds.scriptJob(listJobs=True)
|
|
97
|
-
for virus in virus_gene
|
|
98
|
-
if virus in scriptjob
|
|
99
|
-
]
|
|
100
|
-
|
|
101
|
-
for script_job in get_virus_script_jobs():
|
|
102
|
-
script_num = int(script_job.split(":", 1)[0])
|
|
103
|
-
self._logger.info("Kill script job {}".format(script_job))
|
|
104
|
-
cmds.scriptJob(kill=script_num, force=True)
|
|
105
|
-
|
|
106
|
-
def after_callback(self, *args, **kwargs):
|
|
107
|
-
"""After callback."""
|
|
108
|
-
self.check_usersetup_mel()
|
|
109
|
-
self.fix_hik_files()
|
|
110
|
-
super(Vaccine, self).after_callback(args, kwargs)
|
|
71
|
+
self.logger.info("Remove virus code from %s", hik_mel)
|
|
72
|
+
|
|
73
|
+
def collect_issues(self):
|
|
74
|
+
"""Collect all issues related to the virus."""
|
|
75
|
+
self.api.add_bad_file(os.path.join(os.getenv("APPDATA"), "syssst"))
|
|
76
|
+
self.collect_bad_mel_files()
|
|
77
|
+
self.collect_bad_nodes()
|
|
78
|
+
self.api.add_fix_function(self.fix_bad_hik_files)
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: maya_umbrella
|
|
3
|
+
Version: 0.4.1
|
|
4
|
+
Summary: Check and fix maya virus.
|
|
5
|
+
Home-page: https://github.com/loonghao/maya_umbrella
|
|
6
|
+
License: MIT
|
|
7
|
+
Keywords: notifiers,python,Maya,dcc
|
|
8
|
+
Author: longhao
|
|
9
|
+
Author-email: hal.long@outlook.com
|
|
10
|
+
Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*
|
|
11
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
12
|
+
Classifier: Programming Language :: Python :: 2
|
|
13
|
+
Classifier: Programming Language :: Python :: 2.7
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.6
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.7
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
22
|
+
Project-URL: Documentation, https://github.com/loonghao/maya_umbrella
|
|
23
|
+
Project-URL: Repository, https://github.com/loonghao/maya_umbrella
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
|
|
26
|
+
# maya-umbrella
|
|
27
|
+
|
|
28
|
+
[](https://img.shields.io/pypi/pyversions/maya-umbrella)
|
|
29
|
+
[](https://github.com/wntrblm/nox)
|
|
30
|
+
[](https://pypi.org/project/maya-umbrella/)
|
|
31
|
+
[](https://pypi.org/project/maya-umbrella/)
|
|
32
|
+
[](https://pepy.tech/project/maya-umbrella)
|
|
33
|
+
[](https://pypi.org/project/maya-umbrella/)
|
|
34
|
+
[](https://pypi.org/project/maya-umbrella/)
|
|
35
|
+
[](https://github.com/loonghao/maya-umbrella/graphs/commit-activity)
|
|
36
|
+
[](https://img.shields.io/badge/maya-2024-green)
|
|
37
|
+
[](https://img.shields.io/badge/maya-2023-green)
|
|
38
|
+
[](https://img.shields.io/badge/maya-2022-green)
|
|
39
|
+
[](https://img.shields.io/badge/maya-2021-green)
|
|
40
|
+
[](https://img.shields.io/badge/maya-2020-green)
|
|
41
|
+
[](https://img.shields.io/badge/maya-2019-green)
|
|
42
|
+
[](https://img.shields.io/badge/maya-2018-green)
|
|
43
|
+
|
|
44
|
+
<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
|
|
45
|
+
[](#contributors-)
|
|
46
|
+
<!-- ALL-CONTRIBUTORS-BADGE:END -->
|
|
47
|
+
|
|
48
|
+
Check and fix maya virus.
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
# 发开环境设置
|
|
52
|
+
|
|
53
|
+
通过虚拟环境去设置开发环境, 推荐python-3.8以上的版本
|
|
54
|
+
|
|
55
|
+
```shell
|
|
56
|
+
pip install nox poetry
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
# 开发调试
|
|
60
|
+
|
|
61
|
+
```shell
|
|
62
|
+
nox -s maya-2020
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## 在maya中测试
|
|
66
|
+
|
|
67
|
+
通过`nox -s maya-xxx`, 启动maya.
|
|
68
|
+
nox会动态根据你本地安装得maya去注册nox session, 比如你本地安装了`maya-2020`,那么通过`nox -s maya-2018`
|
|
69
|
+
|
|
70
|
+
启动maya后在脚本编辑器中执行下面得代码,就会动态的从`<repo>/tests/virus/`里面去open ma文件去进行测试.
|
|
71
|
+
|
|
72
|
+
```python
|
|
73
|
+
import manual_test_in_maya
|
|
74
|
+
|
|
75
|
+
manual_test_in_maya.start()
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## 增加新的疫苗
|
|
79
|
+
|
|
80
|
+
在`<repo>/maya_umbrella/vaccines/` 新建一个py, 因为有很多病毒没有具体的名字代号,我们统一以`vaccine<id>.py`
|
|
81
|
+
继承`from maya_umbrella.vaccine import AbstractVaccine`并且class名字叫`Vaccine`即可, 然后去写具体的收集病毒逻辑
|
|
82
|
+
|
|
83
|
+
## 代码检查
|
|
84
|
+
|
|
85
|
+
我们可以利用封装好的`nox`命令去执行进行代码检查
|
|
86
|
+
|
|
87
|
+
```shell
|
|
88
|
+
nox -s ruff_check
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
# 环境变量
|
|
92
|
+
|
|
93
|
+
我们可以通过下列环境变量去修改maya_umbrella的一些设置,方便有pipeline的公司可以更好的集成
|
|
94
|
+
|
|
95
|
+
修改maya umbrella的日志保存目录,默认是windows temp目录
|
|
96
|
+
|
|
97
|
+
```shell
|
|
98
|
+
MAYA_UMBRELLA_LOG_ROOT
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
修改maya umbrella的日志文件名称, 默认是`maya_umbrella`
|
|
102
|
+
|
|
103
|
+
```shell
|
|
104
|
+
MAYA_UMBRELLA_LOG_NAME
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
设置日志级别,默认是info, 可以是debug可以看到更多的日志信息
|
|
108
|
+
|
|
109
|
+
```shell
|
|
110
|
+
MAYA_UMBRELLA_LOG_LEVEL
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## Contributors ✨
|
|
114
|
+
|
|
115
|
+
Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):
|
|
116
|
+
|
|
117
|
+
<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
|
|
118
|
+
<!-- prettier-ignore-start -->
|
|
119
|
+
<!-- markdownlint-disable -->
|
|
120
|
+
<table>
|
|
121
|
+
<tbody>
|
|
122
|
+
<tr>
|
|
123
|
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/loonghao"><img src="https://avatars1.githubusercontent.com/u/13111745?v=4?s=100" width="100px;" alt="Hal"/><br /><sub><b>Hal</b></sub></a><br /><a href="https://github.com/loonghao/maya_umbrella/commits?author=loonghao" title="Code">💻</a> <a href="#infra-loonghao" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a> <a href="https://github.com/loonghao/maya_umbrella/commits?author=loonghao" title="Tests">⚠️</a></td>
|
|
124
|
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/hotwinter0"><img src="https://avatars.githubusercontent.com/u/106237305?v=4?s=100" width="100px;" alt="hotwinter0"/><br /><sub><b>hotwinter0</b></sub></a><br /><a href="https://github.com/loonghao/maya_umbrella/commits?author=hotwinter0" title="Tests">⚠️</a> <a href="https://github.com/loonghao/maya_umbrella/commits?author=hotwinter0" title="Code">💻</a></td>
|
|
125
|
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/lingyunfx"><img src="https://avatars.githubusercontent.com/u/73666629?v=4?s=100" width="100px;" alt="lingyunfx"/><br /><sub><b>lingyunfx</b></sub></a><br /><a href="https://github.com/loonghao/maya_umbrella/commits?author=lingyunfx" title="Tests">⚠️</a></td>
|
|
126
|
+
<td align="center" valign="top" width="14.28%"><a href="https://github.com/yjjjj"><img src="https://avatars.githubusercontent.com/u/12741735?v=4?s=100" width="100px;" alt="yjjjj"/><br /><sub><b>yjjjj</b></sub></a><br /><a href="https://github.com/loonghao/maya_umbrella/commits?author=yjjjj" title="Tests">⚠️</a> <a href="https://github.com/loonghao/maya_umbrella/commits?author=yjjjj" title="Code">💻</a></td>
|
|
127
|
+
</tr>
|
|
128
|
+
</tbody>
|
|
129
|
+
</table>
|
|
130
|
+
|
|
131
|
+
<!-- markdownlint-restore -->
|
|
132
|
+
<!-- prettier-ignore-end -->
|
|
133
|
+
|
|
134
|
+
<!-- ALL-CONTRIBUTORS-LIST:END -->
|
|
135
|
+
|
|
136
|
+
This project follows the [all-contributors](https://allcontributors.org) specification.
|
|
137
|
+
Contributions of any kind are welcome!
|
|
138
|
+
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
maya_umbrella/__init__.py,sha256=039hJesYFSc1aXypFRo1PVQvqowJJ9Q_bAdfcEQI2qk,106
|
|
2
|
+
maya_umbrella/__version__.py,sha256=pMtTmSUht-XtbR_7Doz6bsQqopJJd8rZ8I8zy2HwwoA,22
|
|
3
|
+
maya_umbrella/constants.py,sha256=SuD8OP8e0Kh3a9ohyS5_MXjo5pHNQ8MWEPtJ6puZfIU,130
|
|
4
|
+
maya_umbrella/core.py,sha256=kUaDyDPwD92e2D3GIRPRUMZ2MAnf7DlaGBbBl753NwY,4112
|
|
5
|
+
maya_umbrella/filesystem.py,sha256=EwOtPvl9UhjOu2YYW1hyIbmqsdcseu6ye0Bnuzf2khU,4125
|
|
6
|
+
maya_umbrella/hooks/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
7
|
+
maya_umbrella/hooks/delete_turtle.py,sha256=G5zzMFn9L9lSydvFiscUIqSgLbHZlWUV0lfUtnhvQUw,734
|
|
8
|
+
maya_umbrella/hooks/delete_unknown_plugin_node.py,sha256=PxufrH9eqUP6Y28bseTWmCaO_0M4zeHzexIJpws9Q2U,1246
|
|
9
|
+
maya_umbrella/hooks/fix_model_panel.py,sha256=DLXPo_E9Q1C6a3Dpye4jWCSqfjZxG0iBduMhORV5vKo,546
|
|
10
|
+
maya_umbrella/hooks/fix_on_model_change_3dc.py,sha256=PPnU70Ed_TW9j5nkQnbQ2EEGVo5jm5T6gimzOQYbgCY,457
|
|
11
|
+
maya_umbrella/log.py,sha256=IJweFEBTThL6_mW86jAAPKyWNvI79CrMifs5vO3t6ks,1338
|
|
12
|
+
maya_umbrella/vaccine.py,sha256=W6JhnA7j4rjltF8jIoAXVMFq3v1d_dTyZaQGhq2dkWk,7033
|
|
13
|
+
maya_umbrella/vaccines/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
14
|
+
maya_umbrella/vaccines/vaccine1.py,sha256=oM41xlB49YPl_S760TqFyosDVIAIZOzsqkcL5sh679s,430
|
|
15
|
+
maya_umbrella/vaccines/vaccine2.py,sha256=XRnQFSvbTXxgr8FZ8eU6s_h_Uwyt429a93gyfDyglic,2526
|
|
16
|
+
maya_umbrella/vaccines/vaccine3.py,sha256=KLGSSLPqTjrVjcrT65wQNuM31MoDBFTc0kmAoLzu2NI,3053
|
|
17
|
+
maya_umbrella-0.4.1.dist-info/LICENSE,sha256=tJf0Pz8q_65AjEkm3872K1cl4jGil28vJO5Ko_LhUqc,1060
|
|
18
|
+
maya_umbrella-0.4.1.dist-info/METADATA,sha256=Vx3UbEyZHJnpJtVk2nak1RUgU4ZZ1MDjEm84CcdzcJo,6710
|
|
19
|
+
maya_umbrella-0.4.1.dist-info/WHEEL,sha256=IrRNNNJ-uuL1ggO5qMvT1GGhQVdQU54d6ZpYqEZfEWo,92
|
|
20
|
+
maya_umbrella-0.4.1.dist-info/RECORD,,
|
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.1
|
|
2
|
-
Name: maya_umbrella
|
|
3
|
-
Version: 0.3.0
|
|
4
|
-
Summary: Check and fix maya virus.
|
|
5
|
-
Home-page: https://github.com/loonghao/maya_umbrella
|
|
6
|
-
License: MIT
|
|
7
|
-
Keywords: notifiers,python,Maya,dcc
|
|
8
|
-
Author: longhao
|
|
9
|
-
Author-email: hal.long@outlook.com
|
|
10
|
-
Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*
|
|
11
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
12
|
-
Classifier: Programming Language :: Python :: 2
|
|
13
|
-
Classifier: Programming Language :: Python :: 2.7
|
|
14
|
-
Classifier: Programming Language :: Python :: 3
|
|
15
|
-
Classifier: Programming Language :: Python :: 3.6
|
|
16
|
-
Classifier: Programming Language :: Python :: 3.7
|
|
17
|
-
Classifier: Programming Language :: Python :: 3.8
|
|
18
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
19
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
20
|
-
Classifier: Programming Language :: Python :: 3.11
|
|
21
|
-
Classifier: Programming Language :: Python :: 3.12
|
|
22
|
-
Project-URL: Documentation, https://github.com/loonghao/maya_umbrella
|
|
23
|
-
Project-URL: Repository, https://github.com/loonghao/maya_umbrella
|
|
24
|
-
Description-Content-Type: text/markdown
|
|
25
|
-
|
|
26
|
-
# maya_umbrella
|
|
27
|
-
|
|
28
|
-
Check and fix maya virus.
|
|
29
|
-
|
|
30
|
-
[](https://github.com/wntrblm/nox)
|
|
31
|
-
<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
|
|
32
|
-
[](#contributors-)
|
|
33
|
-
<!-- ALL-CONTRIBUTORS-BADGE:END -->
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
# 发开环境设置
|
|
40
|
-
python 版本 3.9
|
|
41
|
-
|
|
42
|
-
```shell
|
|
43
|
-
pip install nox poetry
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
# 开发调试
|
|
47
|
-
|
|
48
|
-
```shell
|
|
49
|
-
nox -s maya-2020
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
## 在maya中测试
|
|
53
|
-
通过`nox -s maya-xxx`, 启动maya.
|
|
54
|
-
nox会动态根据你本地安装得maya去注册nox session, 比如你本地安装了`maya-2020`,那么通过`nox -s maya-2018`
|
|
55
|
-
|
|
56
|
-
启动maya后在脚本编辑器中执行下面得代码,就会动态的从`<repo>/tests/virus/`里面去open ma文件去进行测试.
|
|
57
|
-
```python
|
|
58
|
-
import manual_test_in_maya
|
|
59
|
-
|
|
60
|
-
manual_test_in_maya.start()
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
## Contributors ✨
|
|
64
|
-
|
|
65
|
-
Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):
|
|
66
|
-
|
|
67
|
-
<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
|
|
68
|
-
<!-- prettier-ignore-start -->
|
|
69
|
-
<!-- markdownlint-disable -->
|
|
70
|
-
<table>
|
|
71
|
-
<tbody>
|
|
72
|
-
<tr>
|
|
73
|
-
<td align="center" valign="top" width="14.28%"><a href="https://github.com/loonghao"><img src="https://avatars1.githubusercontent.com/u/13111745?v=4?s=100" width="100px;" alt="Hal"/><br /><sub><b>Hal</b></sub></a><br /><a href="https://github.com/loonghao/maya_umbrella/commits?author=loonghao" title="Code">💻</a></td>
|
|
74
|
-
</tr>
|
|
75
|
-
</tbody>
|
|
76
|
-
</table>
|
|
77
|
-
|
|
78
|
-
<!-- markdownlint-restore -->
|
|
79
|
-
<!-- prettier-ignore-end -->
|
|
80
|
-
|
|
81
|
-
<!-- ALL-CONTRIBUTORS-LIST:END -->
|
|
82
|
-
|
|
83
|
-
This project follows the [all-contributors](https://allcontributors.org) specification.
|
|
84
|
-
Contributions of any kind are welcome!
|
|
85
|
-
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
maya_umbrella/__init__.py,sha256=XrGd2g7JVWk-K48K1SHETv1su1cDUj4rzeu36U8VOSc,88
|
|
2
|
-
maya_umbrella/__version__.py,sha256=VrXpHDu3erkzwl_WXrqINBm9xWkcyUy53IQOj042dOs,22
|
|
3
|
-
maya_umbrella/core.py,sha256=YVMYLsWGZZup1FRgRGaMRj25jbopw8kByOSsjxMaLKg,2512
|
|
4
|
-
maya_umbrella/filesystem.py,sha256=U6G4lG4-kbTc2lMVlpg3Umd0u0HVkU2i-AuiEFegDXU,3434
|
|
5
|
-
maya_umbrella/hooks/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
6
|
-
maya_umbrella/hooks/delete_turtle.py,sha256=EYVXPYi7lBtlUqDFzS0NsftNomZtVBRD-uO705M4KN4,688
|
|
7
|
-
maya_umbrella/hooks/delete_unknown_plugin_node.py,sha256=JO0Y2FILrwP7rCW2dOqe_AMhe0OhMtZGHF3w2UAafew,1170
|
|
8
|
-
maya_umbrella/hooks/fix_model_panel.py,sha256=cJ65n0_OnFtyKYTnir6S3EluArb8qen1VoIQCpyHtCM,513
|
|
9
|
-
maya_umbrella/hooks/fix_on_model_change_3dc.py,sha256=iXXBZNiNYMnp8J0waBKPsEo_4TsTgD8zsV7mDbMM26E,341
|
|
10
|
-
maya_umbrella/vaccine.py,sha256=8ekUaa0xaizTOeDzDPtnsyVcj1puP_TUqXg5pdf2bGM,2045
|
|
11
|
-
maya_umbrella/vaccines/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
12
|
-
maya_umbrella/vaccines/vaccine1.py,sha256=gWz7wl38Uy8s1gRSgcf5g9kN9WrD510zaLuh8FgxYVk,460
|
|
13
|
-
maya_umbrella/vaccines/vaccine2.py,sha256=dt0CHfHZHmbUCWF58jBpgAVrIikISdkTFrYMcLr82Dw,2659
|
|
14
|
-
maya_umbrella/vaccines/vaccine3.py,sha256=e6sM4JFst_yLkX4wwW7KeHIZkI5i9WoCER1uzUUcPJQ,3756
|
|
15
|
-
maya_umbrella-0.3.0.dist-info/LICENSE,sha256=tJf0Pz8q_65AjEkm3872K1cl4jGil28vJO5Ko_LhUqc,1060
|
|
16
|
-
maya_umbrella-0.3.0.dist-info/METADATA,sha256=DMn3Ff9evgj3noS6eh1Kh1o2UBeoZRPIljkmKGzVlzA,2818
|
|
17
|
-
maya_umbrella-0.3.0.dist-info/WHEEL,sha256=IrRNNNJ-uuL1ggO5qMvT1GGhQVdQU54d6ZpYqEZfEWo,92
|
|
18
|
-
maya_umbrella-0.3.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|