maya-umbrella 0.4.0__py2.py3-none-any.whl → 0.5.0__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.
@@ -1 +1 @@
1
- __version__ = "0.4.0"
1
+ __version__ = "0.5.0"
@@ -3,3 +3,16 @@ PACKAGE_NAME = "maya_umbrella"
3
3
  LOG_FORMAT = "%(asctime)s [%(levelname)s] %(name)s: %(message)s"
4
4
 
5
5
  LOG_MAX_BYTES = 1024 * 1024 * 5
6
+
7
+ FILE_VIRUS_SIGNATURES = [
8
+ "import vaccine",
9
+ "cmds.evalDeferred.*leukocyte.+",
10
+ "python(.*);.+exec.+(pyCode).+;",
11
+ ]
12
+
13
+ JOB_SCRIPTS_VIRUS_SIGNATURES = [
14
+ "petri_dish_path.+cmds.internalVar.+",
15
+ "userSetup",
16
+ "fuckVirus",
17
+ "python(.*);.+exec.+(pyCode).+;",
18
+ ]
maya_umbrella/core.py CHANGED
@@ -1,15 +1,13 @@
1
1
  # Import built-in modules
2
2
  import logging
3
3
 
4
- # Import third-party modules
5
- import maya.api.OpenMaya as om
6
- import maya.cmds as cmds
7
-
8
4
  # Import local modules
9
5
  from maya_umbrella.filesystem import get_hooks
10
6
  from maya_umbrella.filesystem import get_vaccines
11
7
  from maya_umbrella.filesystem import load_hook
12
8
  from maya_umbrella.log import setup_logger
9
+ from maya_umbrella.maya_funs import is_maya_standalone
10
+ from maya_umbrella.maya_funs import om
13
11
  from maya_umbrella.vaccine import MayaVirusCleaner
14
12
 
15
13
 
@@ -63,11 +61,11 @@ class MayaVirusDefender(object):
63
61
 
64
62
  def run_hooks(self):
65
63
  """Run all hooks, only works in non-batch mode."""
66
- if not cmds.about(batch=True):
64
+ if not is_maya_standalone():
67
65
  for hook_file in get_hooks():
68
66
  self.logger.debug("run_hook: %s", hook_file)
69
67
  try:
70
- load_hook(hook_file).hook(self.virus_cleaner)
68
+ load_hook(hook_file).hook(virus_cleaner=self.virus_cleaner)
71
69
  except Exception as e:
72
70
  self.logger.error("Error running hook: %s", e)
73
71
 
@@ -76,13 +74,17 @@ class MayaVirusDefender(object):
76
74
  for vaccine in self.vaccines:
77
75
  vaccine.collect_issues()
78
76
 
77
+ def reset(self):
78
+ """Reset internal buffer."""
79
+ self.virus_cleaner.reset_all_issues()
80
+
79
81
  def fix(self):
80
82
  """Fix all issues related to the Maya virus."""
81
83
  self.virus_cleaner.fix_all_issues()
82
84
 
83
85
  def report(self):
84
86
  """Report all issues related to the Maya virus."""
85
- self.virus_cleaner.reset_all_issues()
87
+ self.reset()
86
88
  self.collect()
87
89
  self.virus_cleaner.report_all_issues()
88
90
 
@@ -106,6 +108,7 @@ class MayaVirusDefender(object):
106
108
  **kwargs: Arbitrary keyword arguments.
107
109
  """
108
110
  if self.auto_fix:
111
+ self.reset()
109
112
  self.collect()
110
113
  self.fix()
111
114
  self.run_hooks()
@@ -1,17 +1,25 @@
1
1
  # Import built-in modules
2
+ from contextlib import contextmanager
2
3
  import glob
3
4
  import importlib
4
- import io
5
+ import logging
5
6
  import os
6
7
  import random
8
+ import re
7
9
  import shutil
8
10
  import string
11
+ import sys
9
12
  import tempfile
10
13
 
11
14
  # Import local modules
15
+ from maya_umbrella.constants import FILE_VIRUS_SIGNATURES
12
16
  from maya_umbrella.constants import PACKAGE_NAME
13
17
 
14
18
 
19
+ PY2 = sys.version_info[0] == 2
20
+ PY3 = sys.version_info[0] == 3
21
+
22
+
15
23
  def this_root():
16
24
  """Return the absolute path of the current file's directory."""
17
25
  return os.path.abspath(os.path.dirname(__file__))
@@ -21,7 +29,7 @@ def safe_remove_file(file_path):
21
29
  """Remove the file at the given path without raising an error if the file does not exist."""
22
30
  try:
23
31
  os.remove(file_path)
24
- except OSError:
32
+ except (OSError, IOError): # noqa: UP024
25
33
  pass
26
34
 
27
35
 
@@ -29,42 +37,38 @@ def safe_rmtree(path):
29
37
  """Remove the directory at the given path without raising an error if the directory does not exist."""
30
38
  try:
31
39
  shutil.rmtree(path)
32
- except OSError:
40
+ except (OSError, IOError): # noqa: UP024
33
41
  pass
34
42
 
35
43
 
36
44
  def read_file(path):
37
45
  """Read the content of the file at the given path."""
38
- with io.open(path, "r", encoding="utf-8") as file_:
39
- content = file_.read()
46
+ options = {"encoding": "utf-8"} if PY3 else {}
47
+ with open(path, **options) as file_:
48
+ try:
49
+ content = file_.read()
50
+ # maya-2022 UnicodeDecodeError from `plug-ins/mayaHIK.pres.mel`
51
+ except UnicodeDecodeError:
52
+ return ""
40
53
  return content
41
54
 
42
55
 
43
56
  def write_file(path, content):
44
57
  """Write the given content to the file at the given path."""
45
- with io.open(path, "w", encoding="utf-8", newline="\n") as file_:
58
+ options = {"encoding": "utf-8"} if PY3 else {}
59
+ with atomic_writes(path, "w", **options) as file_:
46
60
  file_.write(content)
47
61
 
48
62
 
49
- def patch_file(source, target, key_values, report_error=True):
50
- """Modify the file at the source path with the given key value pairs and write the result to the target path.
51
-
52
- If report_error is True, raise an IndexError if any of the keys are not found in the source file.
53
- """
54
- key_values = key_values if key_values else {}
55
- found_keys = []
56
- file_data = read_file(source)
57
- for key, value in key_values.items():
58
- before_ = file_data
59
- file_data = file_data.replace(key, value)
60
- if before_ != file_data:
61
- found_keys.append(key)
62
- write_file(target, file_data)
63
-
64
- if report_error:
65
- not_found = list(set(key_values.keys()) - set(found_keys))
66
- if not_found:
67
- raise IndexError("Not found: {0}".format(not_found))
63
+ @contextmanager
64
+ def atomic_writes(src, mode, **options):
65
+ temp_path = os.path.join(os.path.dirname(src), "._{}".format(id_generator()))
66
+ with open(temp_path, mode, **options) as f:
67
+ yield f
68
+ try:
69
+ os.replace(temp_path, src)
70
+ except AttributeError:
71
+ shutil.move(temp_path, src)
68
72
 
69
73
 
70
74
  def id_generator(size=6, chars=string.ascii_uppercase + string.digits):
@@ -77,7 +81,7 @@ def rename(src):
77
81
  dst = os.path.join(os.path.dirname(src), "._{}".format(id_generator()))
78
82
  try:
79
83
  os.rename(src, dst)
80
- except OSError:
84
+ except (OSError, IOError): # noqa: UP024
81
85
  return src
82
86
  return dst
83
87
 
@@ -88,7 +92,7 @@ def load_hook(hook_file):
88
92
  if hasattr(importlib, "machinery"):
89
93
  # Python 3
90
94
  # Import built-in modules
91
- from importlib.util import spec_from_loader
95
+ from importlib.util import spec_from_loader # noqa: F401
92
96
 
93
97
  loader = importlib.machinery.SourceFileLoader(hook_name, hook_file)
94
98
  spec = importlib.util.spec_from_loader(loader.name, loader=loader)
@@ -110,8 +114,7 @@ def get_hooks():
110
114
 
111
115
 
112
116
  def get_vaccines():
113
- """
114
- Get a list of all vaccine files.
117
+ """Get a list of all vaccine files.
115
118
 
116
119
  Returns:
117
120
  list: A list of vaccine files.
@@ -121,8 +124,7 @@ def get_vaccines():
121
124
 
122
125
 
123
126
  def get_log_root():
124
- """
125
- Get the log root directory.
127
+ """Get the log root directory.
126
128
 
127
129
  Returns:
128
130
  str: The log root directory.
@@ -131,8 +133,7 @@ def get_log_root():
131
133
 
132
134
 
133
135
  def get_log_file():
134
- """
135
- Get the path of the log file.
136
+ """Get the path of the log file.
136
137
 
137
138
  Returns:
138
139
  str: The path of the log file.
@@ -140,7 +141,41 @@ def get_log_file():
140
141
  root = get_log_root()
141
142
  try:
142
143
  os.makedirs(root)
143
- except OSError:
144
+ except (OSError, IOError): # noqa: UP024
144
145
  pass
145
146
  name = os.getenv("MAYA_UMBRELLA_LOG_NAME", PACKAGE_NAME)
146
147
  return os.path.join(root, "{name}.log".format(name=name))
148
+
149
+
150
+ def remove_virus_file_by_signature(file_path, signatures, output_file_path=None):
151
+ logger = logging.getLogger(__name__)
152
+ data = read_file(file_path)
153
+ if check_virus_by_signature(data, signatures):
154
+ logger.warning("%s: Infected by Malware!", file_path)
155
+ fixed_data = replace_content_by_signatures(data, signatures)
156
+ write_file(output_file_path or file_path, fixed_data)
157
+
158
+
159
+ def replace_content_by_signatures(content, signatures):
160
+ for signature in signatures:
161
+ content = re.sub(signature, "", content)
162
+ return content
163
+
164
+
165
+ def check_virus_file_by_signature(file_path, signatures=None):
166
+ signatures = signatures or FILE_VIRUS_SIGNATURES
167
+ try:
168
+ data = read_file(file_path)
169
+ return check_virus_by_signature(data, signatures)
170
+ except (OSError, IOError): # noqa: UP024
171
+ return False
172
+ except UnicodeDecodeError:
173
+ return True
174
+
175
+
176
+ def check_virus_by_signature(content, signatures=None):
177
+ signatures = signatures or FILE_VIRUS_SIGNATURES
178
+ for signature in signatures:
179
+ if re.search(signature, content):
180
+ return True
181
+ return False
@@ -1,6 +1,6 @@
1
- # Import third-party modules
2
- import maya.cmds as cmds
3
- import maya.mel as mel
1
+ # Import local modules
2
+ from maya_umbrella.maya_funs import cmds
3
+ from maya_umbrella.maya_funs import mel
4
4
 
5
5
 
6
6
  def hook(virus_cleaner):
@@ -1,5 +1,5 @@
1
- # Import third-party modules
2
- import maya.cmds as cmds
1
+ # Import local modules
2
+ from maya_umbrella.maya_funs import cmds
3
3
 
4
4
 
5
5
  def hook(virus_cleaner):
@@ -16,7 +16,8 @@ def hook(virus_cleaner):
16
16
  cmds.lockNode(nodeObj, lock=False)
17
17
  except Exception:
18
18
  virus_cleaner.logger.warning(
19
- "The node is locked and cannot be unlocked. skip {}".format(nodeObj))
19
+ "The node is locked and cannot be unlocked. skip {}".format(nodeObj)
20
+ )
20
21
  continue
21
22
  try:
22
23
  cmds.delete(nodeObj)
@@ -1,5 +1,5 @@
1
- # Import third-party modules
2
- import maya.cmds as cmds
1
+ # Import local modules
2
+ from maya_umbrella.maya_funs import cmds
3
3
 
4
4
 
5
5
  def hook(virus_cleaner):
@@ -1,6 +1,6 @@
1
- # Import third-party modules
2
- import maya.cmds as cmds
3
- import maya.mel as mel
1
+ # Import local modules
2
+ from maya_umbrella.maya_funs import cmds
3
+ from maya_umbrella.maya_funs import mel
4
4
 
5
5
 
6
6
  def hook(virus_cleaner):
@@ -0,0 +1,36 @@
1
+ """In order to facilitate unit testing in CI.
2
+
3
+ we extracted all the interfaces used in Maya and mocked them uniformly.
4
+
5
+ """
6
+
7
+ # Import third-party modules
8
+ try:
9
+ # Import third-party modules
10
+ import maya.api.OpenMaya as om
11
+ import maya.cmds as cmds
12
+ import maya.mel as mel
13
+ except ImportError:
14
+ # Backward compatibility to support test in uinstalled maya.
15
+ try:
16
+ # Import built-in modules
17
+ from unittest.mock import MagicMock
18
+ except ImportError:
19
+ # Import third-party modules
20
+ from mock import MagicMock # noqa: UP026
21
+ cmds = MagicMock()
22
+ om = MagicMock()
23
+ mel = MagicMock()
24
+
25
+
26
+ def is_maya_standalone():
27
+ """Return True if Maya is standalone."""
28
+ return cmds.about(batch=True)
29
+
30
+
31
+ def check_reference_node_exists(node_name):
32
+ """Check if reference node exists."""
33
+ try:
34
+ return cmds.referenceQuery(node_name, isNodeReferenced=True)
35
+ except RuntimeError:
36
+ return False
maya_umbrella/vaccine.py CHANGED
@@ -3,17 +3,20 @@ from collections import defaultdict
3
3
  import glob
4
4
  import logging
5
5
  import os
6
-
7
- # Import third-party modules
8
- import maya.cmds as cmds
6
+ import re
9
7
 
10
8
  # Import local modules
9
+ from maya_umbrella.constants import FILE_VIRUS_SIGNATURES
10
+ from maya_umbrella.filesystem import remove_virus_file_by_signature
11
11
  from maya_umbrella.filesystem import safe_remove_file
12
12
  from maya_umbrella.filesystem import safe_rmtree
13
+ from maya_umbrella.maya_funs import check_reference_node_exists
14
+ from maya_umbrella.maya_funs import cmds
13
15
 
14
16
 
15
17
  class MayaVirusCleaner(object):
16
18
  _bad_files = []
19
+ _infected_files = []
17
20
  _bad_nodes = []
18
21
  _bad_script_nodes = []
19
22
  _bad_script_jobs = []
@@ -32,7 +35,7 @@ class MayaVirusCleaner(object):
32
35
  @property
33
36
  def maya_file(self):
34
37
  """Return the current Maya file."""
35
- return cmds.file(q=True, sn=True)
38
+ return cmds.file(query=True, sceneName=True, shortName=True) or "empty/scene"
36
39
 
37
40
  @property
38
41
  def maya_install_root(self):
@@ -69,17 +72,26 @@ class MayaVirusCleaner(object):
69
72
  """Return a list of bad script jobs."""
70
73
  return list(set(self._bad_script_jobs))
71
74
 
75
+ @property
76
+ def infected_files(self):
77
+ return self._infected_files
78
+
72
79
  def callback_remove_rename_temp_files(self, *args, **kwargs):
73
- """
74
- Remove temporary files in the local script path.
75
- """
80
+ """Remove temporary files in the local script path."""
76
81
  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, "._*"))]
82
+ for temp_file in glob.glob(os.path.join(self.local_script_path, "._*")):
83
+ safe_remove_file(temp_file)
78
84
 
79
85
  @property
80
86
  def registered_callbacks(self):
81
87
  return self._registered_callbacks
82
88
 
89
+ def add_infected_files(self, files):
90
+ self._infected_files.extend(files)
91
+
92
+ def add_infected_file(self, file):
93
+ self._infected_files.append(file)
94
+
83
95
  def add_bad_files(self, files):
84
96
  self._bad_files.extend(files)
85
97
 
@@ -145,12 +157,10 @@ class MayaVirusCleaner(object):
145
157
  def add_fix_function(self, func):
146
158
  self._fix_funcs.append(func)
147
159
 
148
- # fix
149
-
150
160
  def fix_script_jobs(self):
151
161
  for script_job in self.bad_script_jobs:
152
- script_num = int(script_job.split(":", 1)[0])
153
- self.logger.info("Kill script job {}".format(script_job))
162
+ script_num = int(re.findall(r"^(\d+):", script_job)[0])
163
+ self.logger.info("Kill script job %s", script_job)
154
164
  cmds.scriptJob(kill=script_num, force=True)
155
165
  self._bad_script_jobs.remove(script_job)
156
166
 
@@ -158,40 +168,60 @@ class MayaVirusCleaner(object):
158
168
  for file_ in self.bad_files:
159
169
  if os.path.exists(file_):
160
170
  if os.path.isfile(file_):
161
- self.logger.info("Removing {}".format(file_))
171
+ self.logger.info("Removing %s", file_)
162
172
  safe_remove_file(file_)
163
173
  self._bad_files.remove(file_)
164
174
  else:
165
- self.logger.info("Removing folder {}".format(file_))
175
+ self.logger.info("Removing folder %s", file_)
166
176
  safe_rmtree(file_)
167
177
  self._bad_files.remove(file_)
168
178
 
169
179
  def fix_bad_nodes(self):
170
180
  for node in self.bad_nodes:
171
181
  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)
182
+ is_referenced = check_reference_node_exists(node)
183
+ if is_referenced:
184
+ try:
185
+ cmds.setAttr("{node}.before".format(node=node), "", type="string")
186
+ cmds.setAttr("{node}.after".format(node=node), "", type="string")
187
+ cmds.setAttr("{node}.scriptType".format(node=node), 0)
188
+ self._bad_nodes.remove(node)
189
+ except Exception as e:
190
+ self.logger.debug(e)
191
+ else:
192
+ try:
193
+ cmds.lockNode(node, lock=False)
194
+ except ValueError:
195
+ pass
196
+ try:
197
+ cmds.delete(node)
198
+ except ValueError:
199
+ pass
200
+ self._bad_nodes.remove(node)
201
+
202
+ def fix_infected_files(self):
203
+ for file_path in self.infected_files:
204
+ self.logger.info("Removing infected file: %s", file_path)
205
+ remove_virus_file_by_signature(file_path, FILE_VIRUS_SIGNATURES)
206
+ self._infected_files.remove(file_path)
181
207
 
182
208
  def fix_all_issues(self):
183
209
  """Fix all issues related to the Maya virus."""
210
+ self.logger.info("Starting Fixing all issues related to the Maya virus from %s.", self.maya_file)
184
211
  self.fix_bad_files()
212
+ self.fix_infected_files()
185
213
  self.fix_bad_nodes()
186
214
  self.fix_script_jobs()
187
215
  for func in self._fix_funcs:
188
216
  func()
217
+ self.logger.info("Finished Fixing all issues related to the Maya virus from %s.", self.maya_file)
189
218
 
190
219
  def report_all_issues(self):
191
220
  """Report all issues related to the Maya virus."""
192
- self.logger.info("Bad files: {}".format(self.bad_files))
193
- self.logger.info("Bad nodes: {}".format(self.bad_nodes))
194
- self.logger.info("Bad script jobs: {}".format(self.bad_script_jobs))
221
+ self.logger.info("Bad files: %s", self.bad_files)
222
+ self.logger.info("Bad nodes: %s", self.bad_nodes)
223
+ self.logger.info("Bad script jobs: %s", self.bad_script_jobs)
224
+ self.logger.info("Infected files: %s", self.infected_files)
195
225
 
196
226
  def reset_all_issues(self):
197
227
  """Reset all issues related to the Maya virus."""
@@ -199,6 +229,7 @@ class MayaVirusCleaner(object):
199
229
  self._bad_nodes = []
200
230
  self._bad_script_nodes = []
201
231
  self._bad_script_jobs = []
232
+ self._infected_files = []
202
233
 
203
234
 
204
235
  class AbstractVaccine(object):
@@ -6,7 +6,7 @@ from maya_umbrella.vaccine import AbstractVaccine
6
6
 
7
7
 
8
8
  class Vaccine(AbstractVaccine):
9
- virus_name = "pu tian tong qi"
9
+ """A class for handling the PuTianTongQi virus."""
10
10
 
11
11
  def collect_issues(self):
12
12
  self.api.add_bad_files(
@@ -1,29 +1,31 @@
1
1
  # Import built-in modules
2
2
  import os.path
3
3
 
4
- # Import third-party modules
5
- import maya.cmds as cmds
6
-
7
4
  # Import local modules
8
- from maya_umbrella.filesystem import read_file
9
- from maya_umbrella.filesystem import rename
5
+ from maya_umbrella.constants import JOB_SCRIPTS_VIRUS_SIGNATURES
6
+ from maya_umbrella.filesystem import check_virus_by_signature
7
+ from maya_umbrella.filesystem import check_virus_file_by_signature
8
+ from maya_umbrella.maya_funs import check_reference_node_exists
9
+ from maya_umbrella.maya_funs import cmds
10
10
  from maya_umbrella.vaccine import AbstractVaccine
11
11
 
12
12
 
13
13
  class Vaccine(AbstractVaccine):
14
+ """A class for handling the ZeiJianKang virus."""
15
+
14
16
  virus_name = "zei jian kang"
15
17
 
16
18
  def collect_bad_nodes(self):
17
19
  """Collect all bad nodes related to the virus."""
18
20
  for script_node in cmds.ls(type="script"):
19
- if cmds.referenceQuery(script_node, isNodeReferenced=True):
21
+ if check_reference_node_exists(script_node):
20
22
  continue
21
23
  script_before_string = cmds.getAttr("{}.before".format(script_node))
22
24
  script_after_string = cmds.getAttr("{}.after".format(script_node))
23
25
  for script_string in [script_before_string, script_after_string]:
24
26
  if not script_string:
25
27
  continue
26
- if "internalVar" in script_string or "userSetup" in script_string or "fuckVirus" in script_string:
28
+ if check_virus_by_signature(script_string, JOB_SCRIPTS_VIRUS_SIGNATURES):
27
29
  self.report_issue(script_node)
28
30
  self.api.add_bad_node(script_node)
29
31
 
@@ -41,20 +43,10 @@ class Vaccine(AbstractVaccine):
41
43
  def collect_bad_usersetup_py(self):
42
44
  """Collect all bad userSetup.py files related to the virus."""
43
45
  for usersetup_py in [
44
- os.path.join(self.api.local_script_path, "vaccine.py"),
45
- os.path.join(self.api.user_script_path, "vaccine.py"),
46
46
  os.path.join(self.api.local_script_path, "userSetup.py"),
47
47
  os.path.join(self.api.user_script_path, "userSetup.py"),
48
48
  ]:
49
49
  if os.path.exists(usersetup_py):
50
- data = read_file(usersetup_py)
51
- if "petri_dish_path = cmds.internalVar(userAppDir=True) + 'scripts/userSetup.py" in data:
52
- self.report_issue("vaccine.py")
53
- self.api.add_bad_file(rename(usersetup_py))
54
-
55
- if (
56
- "cmds.evalDeferred('leukocyte = vaccine.phage()')" in data
57
- and "cmds.evalDeferred('leukocyte.occupation()')" in data
58
- ):
59
- self.report_issue("userSetup.py")
60
- self.api.add_bad_file(rename(usersetup_py))
50
+ if check_virus_file_by_signature(usersetup_py):
51
+ self.report_issue(usersetup_py)
52
+ self.api.add_infected_file(usersetup_py)
@@ -1,20 +1,18 @@
1
1
  # Import built-in modules
2
2
  import glob
3
3
  import os.path
4
- import re
5
-
6
- # Import third-party modules
7
- import maya.cmds as cmds
8
4
 
9
5
  # Import local modules
10
- from maya_umbrella.filesystem import read_file
11
- from maya_umbrella.filesystem import rename
6
+ from maya_umbrella.filesystem import check_virus_file_by_signature
7
+ from maya_umbrella.maya_funs import cmds
8
+ from maya_umbrella.maya_funs import is_maya_standalone
12
9
  from maya_umbrella.vaccine import AbstractVaccine
13
10
 
14
11
 
15
12
  class Vaccine(AbstractVaccine):
13
+ """A class for handling the virus2024429 virus."""
14
+
16
15
  virus_name = "virus2024429"
17
- hik_regex = r"python\(\"import base64;\s*pyCode\s*=\s*base64\.urlsafe_b64decode\([\'\"].*?[\"\']\);\s*exec\s*\(\s*pyCode\s*\)\"\)\s*;"
18
16
 
19
17
  def collect_bad_nodes(self):
20
18
  """Collect all bad nodes related to the virus."""
@@ -23,9 +21,11 @@ class Vaccine(AbstractVaccine):
23
21
  continue
24
22
  # check uifiguration
25
23
  if cmds.objExists("{}.KGMScriptProtector".format(script_node)):
24
+ self.report_issue(script_node)
26
25
  self.api.add_bad_node(script_node)
27
26
  # check vaccine
28
27
  if "_gene" in script_node:
28
+ self.report_issue(script_node)
29
29
  self.api.add_bad_node(script_node)
30
30
 
31
31
  def collect_bad_mel_files(self):
@@ -38,9 +38,9 @@ class Vaccine(AbstractVaccine):
38
38
  os.path.join(self.api.user_script_path, "usersetup.mel"),
39
39
  ]:
40
40
  if os.path.exists(usersetup_mel):
41
- data = read_file(usersetup_mel)
42
- if "import base64; pyCode = base64.urlsafe_b64decode" in data:
43
- self.api.add_bad_file(rename(usersetup_mel))
41
+ if check_virus_file_by_signature(usersetup_mel):
42
+ self.report_issue(usersetup_mel)
43
+ self.api.add_infected_file(usersetup_mel)
44
44
 
45
45
  def collect_script_jobs(self):
46
46
  """Collect all script jobs related to the virus."""
@@ -48,31 +48,25 @@ class Vaccine(AbstractVaccine):
48
48
  "leukocyte",
49
49
  "execute",
50
50
  ]
51
-
52
51
  for script_job in cmds.scriptJob(listJobs=True):
53
52
  for virus in virus_gene:
54
53
  if virus in script_job:
55
- self.api.add_bad_script_jobs(script_job)
54
+ self.api.add_bad_script_job(script_job)
56
55
 
57
56
  def fix_bad_hik_files(self):
58
57
  """Fix all bad HIK files related to the virus."""
59
58
  pattern = os.path.join(self.api.maya_install_root, "resources/l10n/*/plug-ins/mayaHIK.pres.mel")
60
59
  for hik_mel in glob.glob(pattern):
61
- with open(hik_mel, "rb") as f:
62
- data = f.read()
63
- try:
64
- check = re.findall(self.hik_regex, data)
65
- except TypeError:
66
- check = []
67
- if len(check) > 0:
60
+ if check_virus_file_by_signature(hik_mel):
68
61
  self.report_issue(hik_mel)
69
- with open(hik_mel, "wb") as f:
70
- f.write(re.sub(self.hik_regex, "", data))
71
- self.logger.debug("Remove virus code from {}".format(hik_mel))
62
+ self.api.add_infected_file(hik_mel)
72
63
 
73
64
  def collect_issues(self):
74
65
  """Collect all issues related to the virus."""
75
66
  self.api.add_bad_file(os.path.join(os.getenv("APPDATA"), "syssst"))
76
67
  self.collect_bad_mel_files()
77
68
  self.collect_bad_nodes()
69
+ # This only works for Maya Gui model.
70
+ if not is_maya_standalone():
71
+ self.collect_script_jobs()
78
72
  self.api.add_fix_function(self.fix_bad_hik_files)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: maya_umbrella
3
- Version: 0.4.0
3
+ Version: 0.5.0
4
4
  Summary: Check and fix maya virus.
5
5
  Home-page: https://github.com/loonghao/maya_umbrella
6
6
  License: MIT
@@ -28,8 +28,9 @@ Description-Content-Type: text/markdown
28
28
  [![Python Version](https://img.shields.io/pypi/pyversions/maya-umbrella)](https://img.shields.io/pypi/pyversions/maya-umbrella)
29
29
  [![Nox](https://img.shields.io/badge/%F0%9F%A6%8A-Nox-D85E00.svg)](https://github.com/wntrblm/nox)
30
30
  [![PyPI Version](https://img.shields.io/pypi/v/maya-umbrella?color=green)](https://pypi.org/project/maya-umbrella/)
31
- [![Downloads Status](https://img.shields.io/pypi/dw/maya-umbrella)](https://pypi.org/project/maya-umbrella/)
32
- [![Downloads](https://pepy.tech/badge/maya-umbrella)](https://pepy.tech/project/maya-umbrella)
31
+ [![Downloads](https://static.pepy.tech/badge/maya-umbrella)](https://pepy.tech/project/maya-umbrella)
32
+ [![Downloads](https://static.pepy.tech/badge/maya-umbrella/month)](https://pepy.tech/project/maya-umbrella)
33
+ [![Downloads](https://static.pepy.tech/badge/maya-umbrella/week)](https://pepy.tech/project/maya-umbrella)
33
34
  [![License](https://img.shields.io/pypi/l/maya-umbrella)](https://pypi.org/project/maya-umbrella/)
34
35
  [![PyPI Format](https://img.shields.io/pypi/format/maya-umbrella)](https://pypi.org/project/maya-umbrella/)
35
36
  [![Maintenance](https://img.shields.io/badge/Maintained%3F-yes-green.svg)](https://github.com/loonghao/maya-umbrella/graphs/commit-activity)
@@ -45,12 +46,18 @@ Description-Content-Type: text/markdown
45
46
  [![All Contributors](https://img.shields.io/badge/all_contributors-4-orange.svg?style=flat-square)](#contributors-)
46
47
  <!-- ALL-CONTRIBUTORS-BADGE:END -->
47
48
 
48
- Check and fix maya virus.
49
+ This tool is designed to provide a robust solution for identifying and resolving any potential viruses within Autodesk Maya.
50
+ It ensures a secure and seamless user experience by proactively scanning for threats and effectively neutralizing them.
49
51
 
52
+ It can be provided as an API for seamless integration into your existing pipeline.
50
53
 
51
- # 发开环境设置
52
54
 
53
- python 版本 3.9
55
+ # 开发环境设置
56
+
57
+ Set up the development environment using a virtual environment,
58
+ and it is recommended to use Python 3.8 or higher versions.
59
+
60
+ 通过虚拟环境去设置开发环境, 推荐python-3.8以上的版本
54
61
 
55
62
  ```shell
56
63
  pip install nox poetry
@@ -85,9 +92,7 @@ manual_test_in_maya.start()
85
92
  我们可以利用封装好的`nox`命令去执行进行代码检查
86
93
 
87
94
  ```shell
88
- nox -s lint
89
- nox -s black
90
- nox -s isort
95
+ nox -s ruff_check
91
96
  ```
92
97
 
93
98
  # 环境变量
@@ -0,0 +1,21 @@
1
+ maya_umbrella/__init__.py,sha256=039hJesYFSc1aXypFRo1PVQvqowJJ9Q_bAdfcEQI2qk,106
2
+ maya_umbrella/__version__.py,sha256=LBK46heutvn3KmsCrKIYu8RQikbfnjZaj2xFrXaeCzQ,22
3
+ maya_umbrella/constants.py,sha256=1EjxFuDXRW4eSu2lbpfKgGqEhg94rygiXH8UAft7WVU,408
4
+ maya_umbrella/core.py,sha256=4G5Rxdr-3oleEwwZsqQt1q1-f6RdAronbPd8AZuFZfQ,4223
5
+ maya_umbrella/filesystem.py,sha256=6Hkj9GBH4NK_K6-vIGikADf2Bb2om_4Ldsg5blvv1p8,5293
6
+ maya_umbrella/hooks/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
+ maya_umbrella/hooks/delete_turtle.py,sha256=OPFRFH1iwonHvETndrP87MZQlJLhxpe564AJE3KyJY8,761
8
+ maya_umbrella/hooks/delete_unknown_plugin_node.py,sha256=xbJvihfjZBhF946ugVqj2IpY_VjOBZt_8KO5omDrJhw,1281
9
+ maya_umbrella/hooks/fix_model_panel.py,sha256=dLuMOz5uQ1nqAboNWMCx-Bi_gHM3FQNTlGxPG5wRYEs,556
10
+ maya_umbrella/hooks/fix_on_model_change_3dc.py,sha256=o4WEQPcHNzaTMXdNnHZWWNCYlHfLxcSFYXR4YW0ZLwk,484
11
+ maya_umbrella/log.py,sha256=IJweFEBTThL6_mW86jAAPKyWNvI79CrMifs5vO3t6ks,1338
12
+ maya_umbrella/maya_funs.py,sha256=sHmGaec4TsbxleBfHW4K1ige7jU6exhd6oUCxBdf9BQ,951
13
+ maya_umbrella/vaccine.py,sha256=U7WjwScL0suTn2FJNJUCROe4VWUnf1t4ym_4kbOf2I8,8699
14
+ maya_umbrella/vaccines/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
15
+ maya_umbrella/vaccines/vaccine1.py,sha256=EgiIdWn02bmnPz90TMmMLbaxsezkQi7jkrmhrka6m_Q,450
16
+ maya_umbrella/vaccines/vaccine2.py,sha256=oA9FpEyjFuTzRS5AJpYmV41ZYBdLOm_HMhuiM8lmB0E,2151
17
+ maya_umbrella/vaccines/vaccine3.py,sha256=T-AEyqQ9laqHwqIUdZYMfMbt0o7zKX2b9fh3-WnPns0,2869
18
+ maya_umbrella-0.5.0.dist-info/LICENSE,sha256=tJf0Pz8q_65AjEkm3872K1cl4jGil28vJO5Ko_LhUqc,1060
19
+ maya_umbrella-0.5.0.dist-info/METADATA,sha256=ZmYo7E9C-RYIwbnhdIsOAq4upjX6Nc0b2m6BKmeKjXs,7253
20
+ maya_umbrella-0.5.0.dist-info/WHEEL,sha256=IrRNNNJ-uuL1ggO5qMvT1GGhQVdQU54d6ZpYqEZfEWo,92
21
+ maya_umbrella-0.5.0.dist-info/RECORD,,
@@ -1,20 +0,0 @@
1
- maya_umbrella/__init__.py,sha256=039hJesYFSc1aXypFRo1PVQvqowJJ9Q_bAdfcEQI2qk,106
2
- maya_umbrella/__version__.py,sha256=42STGor_9nKYXumfeV5tiyD_M8VdcddX7CEexmibPBk,22
3
- maya_umbrella/constants.py,sha256=SuD8OP8e0Kh3a9ohyS5_MXjo5pHNQ8MWEPtJ6puZfIU,130
4
- maya_umbrella/core.py,sha256=Oo1eR6W5Yft90BrCZ3vezlHzltRdJ5hBi48OaOGPvUM,4098
5
- maya_umbrella/filesystem.py,sha256=nH_HUifzfpI1ynSJr8NGeKuOMJM1Tg1-gsbjUqgvCcI,4140
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=GQrRUXzr1xSRpF74ACoXyVk7auFSQ6dxDIUpBm5hdHU,7075
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=OWIrmLwpt0GmHSTlRpK2iK1u4afoLNhlgQA9_x2wYmo,3061
17
- maya_umbrella-0.4.0.dist-info/LICENSE,sha256=tJf0Pz8q_65AjEkm3872K1cl4jGil28vJO5Ko_LhUqc,1060
18
- maya_umbrella-0.4.0.dist-info/METADATA,sha256=RNXjVA_nhl45pO6e3hoeQNtcpxABfjd7NHr6CYTROuQ,6675
19
- maya_umbrella-0.4.0.dist-info/WHEEL,sha256=IrRNNNJ-uuL1ggO5qMvT1GGhQVdQU54d6ZpYqEZfEWo,92
20
- maya_umbrella-0.4.0.dist-info/RECORD,,