maya-umbrella 0.8.0__tar.gz → 0.10.0__tar.gz
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.
- {maya_umbrella-0.8.0 → maya_umbrella-0.10.0}/PKG-INFO +50 -15
- {maya_umbrella-0.8.0 → maya_umbrella-0.10.0}/README.md +49 -14
- {maya_umbrella-0.8.0 → maya_umbrella-0.10.0}/maya_umbrella/__init__.py +10 -1
- maya_umbrella-0.10.0/maya_umbrella/__version__.py +1 -0
- {maya_umbrella-0.8.0 → maya_umbrella-0.10.0}/maya_umbrella/defender.py +19 -5
- {maya_umbrella-0.8.0 → maya_umbrella-0.10.0}/maya_umbrella/filesystem.py +67 -8
- {maya_umbrella-0.8.0 → maya_umbrella-0.10.0}/maya_umbrella/hooks/delete_unknown_plugin_node.py +12 -12
- {maya_umbrella-0.8.0 → maya_umbrella-0.10.0}/maya_umbrella/i18n.py +2 -2
- {maya_umbrella-0.8.0 → maya_umbrella-0.10.0}/maya_umbrella/log.py +6 -4
- {maya_umbrella-0.8.0 → maya_umbrella-0.10.0}/maya_umbrella/maya_funs.py +1 -1
- {maya_umbrella-0.8.0 → maya_umbrella-0.10.0}/maya_umbrella/scanner.py +2 -2
- {maya_umbrella-0.8.0 → maya_umbrella-0.10.0}/maya_umbrella/vaccines/vaccine2.py +5 -3
- {maya_umbrella-0.8.0 → maya_umbrella-0.10.0}/maya_umbrella/vaccines/vaccine3.py +27 -17
- {maya_umbrella-0.8.0 → maya_umbrella-0.10.0}/pyproject.toml +6 -3
- maya_umbrella-0.8.0/maya_umbrella/__version__.py +0 -1
- {maya_umbrella-0.8.0 → maya_umbrella-0.10.0}/LICENSE +0 -0
- {maya_umbrella-0.8.0 → maya_umbrella-0.10.0}/maya_umbrella/cleaner.py +0 -0
- {maya_umbrella-0.8.0 → maya_umbrella-0.10.0}/maya_umbrella/collector.py +0 -0
- {maya_umbrella-0.8.0 → maya_umbrella-0.10.0}/maya_umbrella/constants.py +0 -0
- {maya_umbrella-0.8.0 → maya_umbrella-0.10.0}/maya_umbrella/hooks/__init__.py +0 -0
- {maya_umbrella-0.8.0 → maya_umbrella-0.10.0}/maya_umbrella/hooks/delete_turtle.py +0 -0
- {maya_umbrella-0.8.0 → maya_umbrella-0.10.0}/maya_umbrella/hooks/fix_model_panel.py +0 -0
- {maya_umbrella-0.8.0 → maya_umbrella-0.10.0}/maya_umbrella/hooks/fix_on_model_change_3dc.py +0 -0
- {maya_umbrella-0.8.0 → maya_umbrella-0.10.0}/maya_umbrella/locales/en_US.json +0 -0
- {maya_umbrella-0.8.0 → maya_umbrella-0.10.0}/maya_umbrella/locales/zh_CN.json +0 -0
- {maya_umbrella-0.8.0 → maya_umbrella-0.10.0}/maya_umbrella/signatures.py +0 -0
- {maya_umbrella-0.8.0 → maya_umbrella-0.10.0}/maya_umbrella/vaccine.py +0 -0
- {maya_umbrella-0.8.0 → maya_umbrella-0.10.0}/maya_umbrella/vaccines/__init__.py +0 -0
- {maya_umbrella-0.8.0 → maya_umbrella-0.10.0}/maya_umbrella/vaccines/vaccine1.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: maya_umbrella
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.10.0
|
|
4
4
|
Summary: Check and fix maya virus.
|
|
5
5
|
Home-page: https://github.com/loonghao/maya_umbrella
|
|
6
6
|
License: MIT
|
|
@@ -53,10 +53,15 @@ It ensures a secure and seamless user experience by proactively scanning for thr
|
|
|
53
53
|
It can be provided as an API for seamless integration into your existing pipeline.
|
|
54
54
|
|
|
55
55
|
# 安装
|
|
56
|
+
|
|
57
|
+
## pip 安装
|
|
56
58
|
maya_umbrella是以标准pipy包去发布的,所以我们可以通过pip install去安装
|
|
57
59
|
```shell
|
|
58
60
|
your/maya-root/mayapy -m pip install maya-umbrella
|
|
59
61
|
```
|
|
62
|
+
## 一键安装
|
|
63
|
+
在release里面下载对应版本的zip包,解压后双击`install.bat`即可安装
|
|
64
|
+
|
|
60
65
|
更新版本
|
|
61
66
|
```shell
|
|
62
67
|
your/maya-root/mayapy -m pip install maya-umbrella --upgrade
|
|
@@ -73,20 +78,25 @@ and it is recommended to use Python 3.8 or higher versions.
|
|
|
73
78
|
|
|
74
79
|
通过虚拟环境去设置开发环境, 推荐python-3.8以上的版本
|
|
75
80
|
|
|
81
|
+
通过pip安装相关开发依赖
|
|
82
|
+
|
|
76
83
|
```shell
|
|
77
|
-
pip install
|
|
84
|
+
pip install -r requirements-dev.txt
|
|
78
85
|
```
|
|
79
86
|
|
|
80
87
|
# 开发调试
|
|
81
88
|
|
|
82
|
-
```shell
|
|
83
|
-
nox -s maya-2020
|
|
84
|
-
```
|
|
85
89
|
|
|
86
90
|
## 在maya中测试
|
|
87
91
|
|
|
88
|
-
通过`nox -s maya
|
|
89
|
-
nox会动态根据你本地安装得maya去注册nox session, 比如你本地安装了`maya-2020
|
|
92
|
+
通过`nox -s maya -- <maya version>`, 启动maya.
|
|
93
|
+
nox会动态根据你本地安装得maya去注册nox session, 比如你本地安装了`maya-2020`,
|
|
94
|
+
那么通过可以启动带有测试环境的maya
|
|
95
|
+
```shell
|
|
96
|
+
nox -s maya -- 2018
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
**注意:maya 与 版本号之间有 俩个`-`**
|
|
90
100
|
|
|
91
101
|
启动maya后在脚本编辑器中执行下面得代码,就会动态的从`<repo>/tests/virus/`里面去open ma文件去进行测试.
|
|
92
102
|
|
|
@@ -96,6 +106,15 @@ import manual_test_in_maya
|
|
|
96
106
|
manual_test_in_maya.start()
|
|
97
107
|
```
|
|
98
108
|
|
|
109
|
+
也可以通过pytest去执行对应的测试,也需要本地安装了对应的maya
|
|
110
|
+
|
|
111
|
+
```shell
|
|
112
|
+
nox -s maya -- 2018 --test
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
**注意:在maya-2022 (PY2) 以下的版本可能会出现命令行crash的情况**
|
|
116
|
+
|
|
117
|
+
|
|
99
118
|
## 增加新的疫苗
|
|
100
119
|
|
|
101
120
|
在`<repo>/maya_umbrella/vaccines/` 新建一个py, 因为有很多病毒没有具体的名字代号,我们统一以`vaccine<id>.py`
|
|
@@ -106,13 +125,20 @@ manual_test_in_maya.start()
|
|
|
106
125
|
我们可以利用封装好的`nox`命令去执行进行代码检查
|
|
107
126
|
|
|
108
127
|
```shell
|
|
109
|
-
nox -s
|
|
128
|
+
nox -s lint
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
进行代码整理
|
|
132
|
+
```shell
|
|
133
|
+
nox -s lint-fix
|
|
110
134
|
```
|
|
111
135
|
|
|
112
136
|
# 生成安装包
|
|
113
137
|
|
|
114
138
|
执行下面的命令可以在<repo>/.zip下面创建zip,参数 `--version` 当前工具的版本号
|
|
115
139
|
|
|
140
|
+
**注意:`make-zip` 与 `--version`之间有 俩个`-`**
|
|
141
|
+
|
|
116
142
|
```shell
|
|
117
143
|
nox -s make-zip -- --version 0.5.0
|
|
118
144
|
```
|
|
@@ -155,14 +181,20 @@ MAYA_UMBRELLA_LANG
|
|
|
155
181
|
MAYA_UMBRELLA_IGNORE_BACKUP
|
|
156
182
|
```
|
|
157
183
|
|
|
184
|
+
如果忽略请设置为
|
|
185
|
+
```shell
|
|
186
|
+
SET MAYA_UMBRELLA_IGNORE_BACKUP=true
|
|
187
|
+
```
|
|
188
|
+
|
|
158
189
|
如果是便携版Maya,可以通过添加 `MAYA_LOCATION` 环境变量指定Maya路径
|
|
159
190
|
```shell
|
|
160
191
|
SET MAYA_LOCATION=d:/your/path/maya_version/
|
|
161
192
|
```
|
|
193
|
+
也可以通过命令行指定目录
|
|
162
194
|
|
|
163
|
-
如果忽略请设置为
|
|
164
195
|
```shell
|
|
165
|
-
|
|
196
|
+
nox -s maya -- 2018 --install-root /your/local/maya/root
|
|
197
|
+
|
|
166
198
|
```
|
|
167
199
|
|
|
168
200
|
# API
|
|
@@ -185,13 +217,16 @@ print(api.scan_files_from_pattern("your/path/*.m[ab]"))
|
|
|
185
217
|
```
|
|
186
218
|
|
|
187
219
|
# 案例
|
|
188
|
-
如果你想要快速通过maya standalone去批量清理maya
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
220
|
+
如果你想要快速通过maya standalone去批量清理maya文件,
|
|
221
|
+
可以`下载`或者`git clone`当前`main`分支的工程,
|
|
222
|
+
根据上面指引设置好开发环境,
|
|
223
|
+
通过`nox`命令去启动maya `standalone`环境,maya版本根据你当前本地安装的maya为准,
|
|
224
|
+
比如你本地安装了`2018`,
|
|
225
|
+
那么就是 `nox -s maya -- 2018 --standalone`
|
|
192
226
|
下面的语法是启动一个maya-2020的环境去动态从`c:/test`文件夹下去查杀病毒
|
|
227
|
+
|
|
193
228
|
```shell
|
|
194
|
-
nox -s maya
|
|
229
|
+
nox -s maya -- 2018 --standalone --pattern c:/test/*.m[ab]
|
|
195
230
|
```
|
|
196
231
|
|
|
197
232
|
## Contributors ✨
|
|
@@ -28,10 +28,15 @@ It ensures a secure and seamless user experience by proactively scanning for thr
|
|
|
28
28
|
It can be provided as an API for seamless integration into your existing pipeline.
|
|
29
29
|
|
|
30
30
|
# 安装
|
|
31
|
+
|
|
32
|
+
## pip 安装
|
|
31
33
|
maya_umbrella是以标准pipy包去发布的,所以我们可以通过pip install去安装
|
|
32
34
|
```shell
|
|
33
35
|
your/maya-root/mayapy -m pip install maya-umbrella
|
|
34
36
|
```
|
|
37
|
+
## 一键安装
|
|
38
|
+
在release里面下载对应版本的zip包,解压后双击`install.bat`即可安装
|
|
39
|
+
|
|
35
40
|
更新版本
|
|
36
41
|
```shell
|
|
37
42
|
your/maya-root/mayapy -m pip install maya-umbrella --upgrade
|
|
@@ -48,20 +53,25 @@ and it is recommended to use Python 3.8 or higher versions.
|
|
|
48
53
|
|
|
49
54
|
通过虚拟环境去设置开发环境, 推荐python-3.8以上的版本
|
|
50
55
|
|
|
56
|
+
通过pip安装相关开发依赖
|
|
57
|
+
|
|
51
58
|
```shell
|
|
52
|
-
pip install
|
|
59
|
+
pip install -r requirements-dev.txt
|
|
53
60
|
```
|
|
54
61
|
|
|
55
62
|
# 开发调试
|
|
56
63
|
|
|
57
|
-
```shell
|
|
58
|
-
nox -s maya-2020
|
|
59
|
-
```
|
|
60
64
|
|
|
61
65
|
## 在maya中测试
|
|
62
66
|
|
|
63
|
-
通过`nox -s maya
|
|
64
|
-
nox会动态根据你本地安装得maya去注册nox session, 比如你本地安装了`maya-2020
|
|
67
|
+
通过`nox -s maya -- <maya version>`, 启动maya.
|
|
68
|
+
nox会动态根据你本地安装得maya去注册nox session, 比如你本地安装了`maya-2020`,
|
|
69
|
+
那么通过可以启动带有测试环境的maya
|
|
70
|
+
```shell
|
|
71
|
+
nox -s maya -- 2018
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
**注意:maya 与 版本号之间有 俩个`-`**
|
|
65
75
|
|
|
66
76
|
启动maya后在脚本编辑器中执行下面得代码,就会动态的从`<repo>/tests/virus/`里面去open ma文件去进行测试.
|
|
67
77
|
|
|
@@ -71,6 +81,15 @@ import manual_test_in_maya
|
|
|
71
81
|
manual_test_in_maya.start()
|
|
72
82
|
```
|
|
73
83
|
|
|
84
|
+
也可以通过pytest去执行对应的测试,也需要本地安装了对应的maya
|
|
85
|
+
|
|
86
|
+
```shell
|
|
87
|
+
nox -s maya -- 2018 --test
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
**注意:在maya-2022 (PY2) 以下的版本可能会出现命令行crash的情况**
|
|
91
|
+
|
|
92
|
+
|
|
74
93
|
## 增加新的疫苗
|
|
75
94
|
|
|
76
95
|
在`<repo>/maya_umbrella/vaccines/` 新建一个py, 因为有很多病毒没有具体的名字代号,我们统一以`vaccine<id>.py`
|
|
@@ -81,13 +100,20 @@ manual_test_in_maya.start()
|
|
|
81
100
|
我们可以利用封装好的`nox`命令去执行进行代码检查
|
|
82
101
|
|
|
83
102
|
```shell
|
|
84
|
-
nox -s
|
|
103
|
+
nox -s lint
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
进行代码整理
|
|
107
|
+
```shell
|
|
108
|
+
nox -s lint-fix
|
|
85
109
|
```
|
|
86
110
|
|
|
87
111
|
# 生成安装包
|
|
88
112
|
|
|
89
113
|
执行下面的命令可以在<repo>/.zip下面创建zip,参数 `--version` 当前工具的版本号
|
|
90
114
|
|
|
115
|
+
**注意:`make-zip` 与 `--version`之间有 俩个`-`**
|
|
116
|
+
|
|
91
117
|
```shell
|
|
92
118
|
nox -s make-zip -- --version 0.5.0
|
|
93
119
|
```
|
|
@@ -130,14 +156,20 @@ MAYA_UMBRELLA_LANG
|
|
|
130
156
|
MAYA_UMBRELLA_IGNORE_BACKUP
|
|
131
157
|
```
|
|
132
158
|
|
|
159
|
+
如果忽略请设置为
|
|
160
|
+
```shell
|
|
161
|
+
SET MAYA_UMBRELLA_IGNORE_BACKUP=true
|
|
162
|
+
```
|
|
163
|
+
|
|
133
164
|
如果是便携版Maya,可以通过添加 `MAYA_LOCATION` 环境变量指定Maya路径
|
|
134
165
|
```shell
|
|
135
166
|
SET MAYA_LOCATION=d:/your/path/maya_version/
|
|
136
167
|
```
|
|
168
|
+
也可以通过命令行指定目录
|
|
137
169
|
|
|
138
|
-
如果忽略请设置为
|
|
139
170
|
```shell
|
|
140
|
-
|
|
171
|
+
nox -s maya -- 2018 --install-root /your/local/maya/root
|
|
172
|
+
|
|
141
173
|
```
|
|
142
174
|
|
|
143
175
|
# API
|
|
@@ -160,13 +192,16 @@ print(api.scan_files_from_pattern("your/path/*.m[ab]"))
|
|
|
160
192
|
```
|
|
161
193
|
|
|
162
194
|
# 案例
|
|
163
|
-
如果你想要快速通过maya standalone去批量清理maya
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
195
|
+
如果你想要快速通过maya standalone去批量清理maya文件,
|
|
196
|
+
可以`下载`或者`git clone`当前`main`分支的工程,
|
|
197
|
+
根据上面指引设置好开发环境,
|
|
198
|
+
通过`nox`命令去启动maya `standalone`环境,maya版本根据你当前本地安装的maya为准,
|
|
199
|
+
比如你本地安装了`2018`,
|
|
200
|
+
那么就是 `nox -s maya -- 2018 --standalone`
|
|
167
201
|
下面的语法是启动一个maya-2020的环境去动态从`c:/test`文件夹下去查杀病毒
|
|
202
|
+
|
|
168
203
|
```shell
|
|
169
|
-
nox -s maya
|
|
204
|
+
nox -s maya -- 2018 --standalone --pattern c:/test/*.m[ab]
|
|
170
205
|
```
|
|
171
206
|
|
|
172
207
|
## Contributors ✨
|
|
@@ -3,7 +3,16 @@ from maya_umbrella.cleaner import MayaVirusCleaner
|
|
|
3
3
|
from maya_umbrella.collector import MayaVirusCollector
|
|
4
4
|
from maya_umbrella.defender import MayaVirusDefender
|
|
5
5
|
from maya_umbrella.defender import context_defender
|
|
6
|
+
from maya_umbrella.defender import get_defender_instance
|
|
6
7
|
from maya_umbrella.scanner import MayaVirusScanner
|
|
7
8
|
|
|
8
9
|
|
|
9
|
-
|
|
10
|
+
# All public APIs.
|
|
11
|
+
__all__ = [
|
|
12
|
+
"MayaVirusDefender",
|
|
13
|
+
"MayaVirusCleaner",
|
|
14
|
+
"MayaVirusCollector",
|
|
15
|
+
"MayaVirusScanner",
|
|
16
|
+
"context_defender",
|
|
17
|
+
"get_defender_instance",
|
|
18
|
+
]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.10.0"
|
|
@@ -15,6 +15,7 @@ from maya_umbrella.maya_funs import om
|
|
|
15
15
|
|
|
16
16
|
# Global list to store IDs of Maya callbacks
|
|
17
17
|
MAYA_UMBRELLA_CALLBACK_IDS = []
|
|
18
|
+
MAYA_UMBRELLA_DEFENDER = None
|
|
18
19
|
|
|
19
20
|
|
|
20
21
|
def _add_callbacks_id(id_):
|
|
@@ -115,10 +116,11 @@ class MayaVirusDefender(object):
|
|
|
115
116
|
|
|
116
117
|
def stop(self):
|
|
117
118
|
"""Stop the MayaVirusDefender."""
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
119
|
+
while MAYA_UMBRELLA_CALLBACK_IDS:
|
|
120
|
+
for ids in MAYA_UMBRELLA_CALLBACK_IDS:
|
|
121
|
+
self.logger.debug("remove callback. %s", ids)
|
|
122
|
+
om.MSceneMessage.removeCallback(ids)
|
|
123
|
+
MAYA_UMBRELLA_CALLBACK_IDS.remove(ids)
|
|
122
124
|
|
|
123
125
|
def get_unfixed_references(self):
|
|
124
126
|
"""Get the list of unfixed reference files.
|
|
@@ -155,7 +157,19 @@ def context_defender():
|
|
|
155
157
|
Yields:
|
|
156
158
|
MayaVirusDefender: An instance of MayaVirusDefender.
|
|
157
159
|
"""
|
|
158
|
-
defender =
|
|
160
|
+
defender = get_defender_instance()
|
|
159
161
|
defender.stop()
|
|
160
162
|
yield defender
|
|
161
163
|
defender.setup()
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
def get_defender_instance():
|
|
167
|
+
"""Get the MayaVirusDefender instance.
|
|
168
|
+
|
|
169
|
+
Returns:
|
|
170
|
+
MayaVirusDefender: The MayaVirusDefender instance.
|
|
171
|
+
"""
|
|
172
|
+
global MAYA_UMBRELLA_DEFENDER
|
|
173
|
+
if MAYA_UMBRELLA_DEFENDER is None:
|
|
174
|
+
MAYA_UMBRELLA_DEFENDER = MayaVirusDefender()
|
|
175
|
+
return MAYA_UMBRELLA_DEFENDER
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
# Import built-in modules
|
|
2
|
+
import codecs
|
|
2
3
|
from contextlib import contextmanager
|
|
3
4
|
import glob
|
|
4
5
|
import importlib
|
|
5
6
|
import json
|
|
7
|
+
import logging
|
|
6
8
|
import os
|
|
7
9
|
import random
|
|
8
10
|
import re
|
|
@@ -41,6 +43,22 @@ def safe_rmtree(path):
|
|
|
41
43
|
pass
|
|
42
44
|
|
|
43
45
|
|
|
46
|
+
def _codes_open(path, encoding="utf-8"):
|
|
47
|
+
"""Open and read the content of a file using the specified encoding.
|
|
48
|
+
|
|
49
|
+
Args:
|
|
50
|
+
path (str): Path to the file.
|
|
51
|
+
encoding (str, optional): The encoding to use when reading the file. Defaults to "utf-8".
|
|
52
|
+
|
|
53
|
+
Returns:
|
|
54
|
+
str: The content of the file, or an empty string if the file could not be read.
|
|
55
|
+
"""
|
|
56
|
+
try:
|
|
57
|
+
with codecs.open(path, "r", encoding) as file_:
|
|
58
|
+
return file_.read()
|
|
59
|
+
except (OSError, IOError): # noqa: UP024
|
|
60
|
+
return ""
|
|
61
|
+
|
|
44
62
|
def read_file(path):
|
|
45
63
|
"""Read the content of the file at the given path."""
|
|
46
64
|
options = {"encoding": "utf-8"} if PY3 else {}
|
|
@@ -89,7 +107,8 @@ def atomic_writes(src, mode, **options):
|
|
|
89
107
|
AttributeError: If the os module does not have the 'replace' function (Python 2 compatibility).
|
|
90
108
|
"""
|
|
91
109
|
temp_path = os.path.join(os.path.dirname(src), "._{}".format(id_generator()))
|
|
92
|
-
|
|
110
|
+
open_func = open if PY3 else codecs.open
|
|
111
|
+
with open_func(temp_path, mode, **options) as f:
|
|
93
112
|
yield f
|
|
94
113
|
try:
|
|
95
114
|
os.replace(temp_path, src)
|
|
@@ -97,7 +116,6 @@ def atomic_writes(src, mode, **options):
|
|
|
97
116
|
shutil.move(temp_path, src)
|
|
98
117
|
|
|
99
118
|
|
|
100
|
-
|
|
101
119
|
def id_generator(size=6, chars=string.ascii_uppercase + string.digits):
|
|
102
120
|
"""Generate a random string of the given size using the given characters."""
|
|
103
121
|
return "".join(random.choice(chars) for _ in range(size))
|
|
@@ -174,7 +192,7 @@ def get_log_file():
|
|
|
174
192
|
return os.path.join(root, "{name}.log".format(name=name))
|
|
175
193
|
|
|
176
194
|
|
|
177
|
-
def remove_virus_file_by_signature(file_path, signatures, output_file_path=None):
|
|
195
|
+
def remove_virus_file_by_signature(file_path, signatures, output_file_path=None, auto_remove=True):
|
|
178
196
|
"""Remove virus content from a file by matching signatures.
|
|
179
197
|
|
|
180
198
|
Args:
|
|
@@ -182,11 +200,23 @@ def remove_virus_file_by_signature(file_path, signatures, output_file_path=None)
|
|
|
182
200
|
signatures (list): List of signatures to match and remove.
|
|
183
201
|
output_file_path (str, optional): Path to the cleaned output file.
|
|
184
202
|
Defaults to None, which overwrites the input file.
|
|
203
|
+
auto_remove: If True, remove the input file if the output file is empty.
|
|
204
|
+
|
|
185
205
|
"""
|
|
186
|
-
|
|
206
|
+
try:
|
|
207
|
+
data = read_file(file_path)
|
|
208
|
+
except (OSError, IOError): # noqa: UP024
|
|
209
|
+
return False
|
|
210
|
+
except UnicodeDecodeError:
|
|
211
|
+
data = _codes_open(file_path)
|
|
187
212
|
if check_virus_by_signature(data, signatures):
|
|
188
|
-
fixed_data = replace_content_by_signatures(data, signatures)
|
|
189
|
-
|
|
213
|
+
fixed_data = replace_content_by_signatures(data, signatures).strip()
|
|
214
|
+
if fixed_data:
|
|
215
|
+
write_file(output_file_path or file_path, fixed_data)
|
|
216
|
+
else:
|
|
217
|
+
# Auto remove empty files.
|
|
218
|
+
if auto_remove:
|
|
219
|
+
os.remove(file_path)
|
|
190
220
|
|
|
191
221
|
|
|
192
222
|
def replace_content_by_signatures(content, signatures):
|
|
@@ -217,11 +247,11 @@ def check_virus_file_by_signature(file_path, signatures=None):
|
|
|
217
247
|
signatures = signatures or FILE_VIRUS_SIGNATURES
|
|
218
248
|
try:
|
|
219
249
|
data = read_file(file_path)
|
|
220
|
-
return check_virus_by_signature(data, signatures)
|
|
221
250
|
except (OSError, IOError): # noqa: UP024
|
|
222
251
|
return False
|
|
223
252
|
except UnicodeDecodeError:
|
|
224
|
-
|
|
253
|
+
data = _codes_open(file_path)
|
|
254
|
+
return check_virus_by_signature(data, signatures)
|
|
225
255
|
|
|
226
256
|
|
|
227
257
|
def check_virus_by_signature(content, signatures=None):
|
|
@@ -266,3 +296,32 @@ def get_backup_path(path, root_path=None):
|
|
|
266
296
|
except (OSError, IOError): # noqa: UP024
|
|
267
297
|
pass
|
|
268
298
|
return os.path.join(backup_path, filename)
|
|
299
|
+
|
|
300
|
+
|
|
301
|
+
def get_maya_install_root(maya_version):
|
|
302
|
+
"""Get the Maya install root path."""
|
|
303
|
+
logger = logging.getLogger(__name__)
|
|
304
|
+
maya_location = os.getenv("MAYA_LOCATION")
|
|
305
|
+
try:
|
|
306
|
+
# Import built-in modules
|
|
307
|
+
import winreg
|
|
308
|
+
except ImportError:
|
|
309
|
+
return maya_location
|
|
310
|
+
try:
|
|
311
|
+
key = winreg.OpenKey(
|
|
312
|
+
winreg.HKEY_LOCAL_MACHINE,
|
|
313
|
+
"SOFTWARE\\Autodesk\\Maya\\{maya_version}\\Setup\\InstallPath".format(maya_version=maya_version),
|
|
314
|
+
)
|
|
315
|
+
root, _ = winreg.QueryValueEx(key, "MAYA_INSTALL_LOCATION")
|
|
316
|
+
if not os.path.isdir(root):
|
|
317
|
+
logger.info("Failed to locate the appropriate Maya path in the registration list.")
|
|
318
|
+
except OSError:
|
|
319
|
+
return maya_location
|
|
320
|
+
maya_location = maya_location or root
|
|
321
|
+
if not maya_location:
|
|
322
|
+
logger.info("maya not found.")
|
|
323
|
+
return
|
|
324
|
+
maya_exe = os.path.join(maya_location, "bin", "maya.exe")
|
|
325
|
+
if not os.path.exists(maya_exe):
|
|
326
|
+
logger.info("maya.exe not found in {maya_location}.".format(maya_location=maya_location))
|
|
327
|
+
return maya_location
|
{maya_umbrella-0.8.0 → maya_umbrella-0.10.0}/maya_umbrella/hooks/delete_unknown_plugin_node.py
RENAMED
|
@@ -6,26 +6,26 @@ 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
|
-
for
|
|
10
|
-
if cmds.objExists(
|
|
11
|
-
if cmds.referenceQuery(
|
|
12
|
-
virus_cleaner.logger.warning("Node from reference, skip. {}".format(
|
|
9
|
+
for node_obj in unknown_node:
|
|
10
|
+
if cmds.objExists(node_obj):
|
|
11
|
+
if cmds.referenceQuery(node_obj, isNodeReferenced=True):
|
|
12
|
+
virus_cleaner.logger.warning("Node from reference, skip. {}".format(node_obj))
|
|
13
13
|
continue
|
|
14
|
-
if cmds.lockNode(
|
|
14
|
+
if cmds.lockNode(node_obj, query=True)[0]:
|
|
15
15
|
try:
|
|
16
|
-
cmds.lockNode(
|
|
16
|
+
cmds.lockNode(node_obj, lock=False)
|
|
17
17
|
except Exception:
|
|
18
18
|
virus_cleaner.logger.warning(
|
|
19
|
-
"The node is locked and cannot be unlocked. skip {}".format(
|
|
19
|
+
"The node is locked and cannot be unlocked. skip {}".format(node_obj)
|
|
20
20
|
)
|
|
21
21
|
continue
|
|
22
22
|
try:
|
|
23
|
-
cmds.delete(
|
|
24
|
-
virus_cleaner.logger.warning("Delete node: {}".format(
|
|
23
|
+
cmds.delete(node_obj)
|
|
24
|
+
virus_cleaner.logger.warning("Delete node: {}".format(node_obj))
|
|
25
25
|
except Exception:
|
|
26
26
|
pass
|
|
27
27
|
|
|
28
28
|
if unknown_plugin:
|
|
29
|
-
for
|
|
30
|
-
cmds.unknownPlugin(
|
|
31
|
-
virus_cleaner.logger.warning("Delete plug-in: {}".format(
|
|
29
|
+
for plug_obj in unknown_plugin:
|
|
30
|
+
cmds.unknownPlugin(plug_obj, remove=True)
|
|
31
|
+
virus_cleaner.logger.warning("Delete plug-in: {}".format(plug_obj))
|
|
@@ -16,6 +16,7 @@ class Translator(object):
|
|
|
16
16
|
data (dict): Dictionary containing translation data for different locales.
|
|
17
17
|
locale (str): The current locale.
|
|
18
18
|
"""
|
|
19
|
+
|
|
19
20
|
def __init__(self, file_format="json", default_locale=None):
|
|
20
21
|
"""Initialize the Translator.
|
|
21
22
|
|
|
@@ -24,8 +25,7 @@ class Translator(object):
|
|
|
24
25
|
default_locale (str, optional): Default locale to use for translations. Defaults to None,
|
|
25
26
|
which uses the MAYA_UMBRELLA_LANG environment variable or the Maya UI language.
|
|
26
27
|
"""
|
|
27
|
-
|
|
28
|
-
default_locale = default_locale or _default_locale
|
|
28
|
+
default_locale = default_locale or os.getenv("MAYA_UMBRELLA_LANG", maya_ui_language())
|
|
29
29
|
self.data = {}
|
|
30
30
|
self.locale = default_locale
|
|
31
31
|
translations_folder = os.path.join(this_root(), "locales")
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# Import built-in modules
|
|
2
|
-
import
|
|
2
|
+
from logging import Formatter
|
|
3
|
+
from logging import getLogger
|
|
4
|
+
from logging import handlers
|
|
3
5
|
import os
|
|
4
6
|
|
|
5
7
|
# Import local modules
|
|
@@ -20,18 +22,18 @@ def setup_logger(logger=None, logfile=None, log_level=None):
|
|
|
20
22
|
Returns:
|
|
21
23
|
logging.Logger: The set up logger.
|
|
22
24
|
"""
|
|
23
|
-
logger = logger or
|
|
25
|
+
logger = logger or getLogger(PACKAGE_NAME)
|
|
24
26
|
log_level = log_level or os.getenv("MAYA_UMBRELLA_LOG_LEVEL", "INFO")
|
|
25
27
|
logger.setLevel(log_level)
|
|
26
28
|
logfile = logfile or get_log_file()
|
|
27
29
|
if not len(logger.handlers):
|
|
28
|
-
filehandler =
|
|
30
|
+
filehandler = handlers.RotatingFileHandler(
|
|
29
31
|
logfile,
|
|
30
32
|
mode="a",
|
|
31
33
|
backupCount=7,
|
|
32
34
|
delay=True,
|
|
33
35
|
maxBytes=LOG_MAX_BYTES,
|
|
34
36
|
)
|
|
35
|
-
filehandler.setFormatter(
|
|
37
|
+
filehandler.setFormatter(Formatter(LOG_FORMAT))
|
|
36
38
|
logger.addHandler(filehandler)
|
|
37
39
|
return logger
|
|
@@ -30,7 +30,7 @@ class MayaVirusScanner(object):
|
|
|
30
30
|
|
|
31
31
|
Args:
|
|
32
32
|
output_path (str, optional): Path to save the fixed files. Defaults to None, which overwrites the original
|
|
33
|
-
|
|
33
|
+
files.
|
|
34
34
|
env (dict, optional): Custom environment variables. Defaults to None,
|
|
35
35
|
which sets the 'MAYA_COLOR_MANAGEMENT_SYNCOLOR' variable to '1'.
|
|
36
36
|
"""
|
|
@@ -99,7 +99,7 @@ class MayaVirusScanner(object):
|
|
|
99
99
|
backup_path = get_backup_path(maya_file, root_path=self.output_path)
|
|
100
100
|
self.logger.debug("Backup saved to: {backup_path}".format(backup_path=backup_path))
|
|
101
101
|
shutil.copy2(maya_file, backup_path)
|
|
102
|
-
cmds.file(
|
|
102
|
+
cmds.file(save=True, force=True)
|
|
103
103
|
self._fixed_files.append(maya_file)
|
|
104
104
|
self._reference_files.extend(self.defender.collector.infected_reference_files)
|
|
105
105
|
cmds.file(new=True, force=True)
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
# Import built-in modules
|
|
2
|
-
import os
|
|
2
|
+
import os
|
|
3
3
|
|
|
4
4
|
# Import local modules
|
|
5
5
|
from maya_umbrella.constants import JOB_SCRIPTS_VIRUS_SIGNATURES
|
|
@@ -42,10 +42,12 @@ class Vaccine(AbstractVaccine):
|
|
|
42
42
|
|
|
43
43
|
def collect_infected_user_setup_py(self):
|
|
44
44
|
"""Collect all bad userSetup.py files related to the virus."""
|
|
45
|
-
|
|
45
|
+
user_setup_py_files = [
|
|
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
|
+
|
|
50
|
+
for user_setup_py in user_setup_py_files:
|
|
49
51
|
if os.path.exists(user_setup_py):
|
|
50
52
|
if check_virus_file_by_signature(user_setup_py):
|
|
51
53
|
self.report_issue(user_setup_py)
|
|
@@ -18,37 +18,47 @@ class Vaccine(AbstractVaccine):
|
|
|
18
18
|
|
|
19
19
|
virus_name = "Virus2024429"
|
|
20
20
|
|
|
21
|
+
@staticmethod
|
|
22
|
+
def is_infected(script_node):
|
|
23
|
+
"""Check if a script node is infected with a virus.
|
|
24
|
+
|
|
25
|
+
Args:
|
|
26
|
+
script_node (str): The name of the script node to check.
|
|
27
|
+
|
|
28
|
+
Returns:
|
|
29
|
+
bool: True if the script node is infected, False otherwise.
|
|
30
|
+
"""
|
|
31
|
+
if "_gene" in script_node:
|
|
32
|
+
return True
|
|
33
|
+
if "uifiguration" in script_node:
|
|
34
|
+
for attr_name in ("before", "notes"):
|
|
35
|
+
script_string = get_attr_value(script_node, attr_name)
|
|
36
|
+
if script_string and check_virus_by_signature(script_string, JOB_SCRIPTS_VIRUS_SIGNATURES):
|
|
37
|
+
return True
|
|
38
|
+
return False
|
|
39
|
+
|
|
21
40
|
def collect_infected_nodes(self):
|
|
22
41
|
"""Collect all bad nodes related to the virus."""
|
|
23
42
|
for script_node in cmds.ls(type="script"):
|
|
24
|
-
|
|
25
|
-
if "_gene" in script_node:
|
|
43
|
+
if self.is_infected(script_node):
|
|
26
44
|
self.report_issue(script_node)
|
|
27
45
|
self.api.add_infected_node(script_node)
|
|
28
46
|
self.api.add_infected_reference_file(get_reference_file_by_node(script_node))
|
|
29
|
-
if "uifiguration" in script_node:
|
|
30
|
-
for attr_name in ("before", "notes"):
|
|
31
|
-
script_string = get_attr_value(script_node, attr_name)
|
|
32
|
-
if not script_string:
|
|
33
|
-
continue
|
|
34
|
-
if check_virus_by_signature(script_string, JOB_SCRIPTS_VIRUS_SIGNATURES):
|
|
35
|
-
self.report_issue(script_node)
|
|
36
|
-
self.api.add_infected_node(script_node)
|
|
37
|
-
self.api.add_infected_reference_file(get_reference_file_by_node(script_node))
|
|
38
47
|
|
|
39
48
|
def collect_infected_mel_files(self):
|
|
40
49
|
"""Collect all bad MEL files related to the virus."""
|
|
41
50
|
# check usersetup.mel
|
|
42
51
|
# C:/Users/hallong/Documents/maya/scripts/usersetup.mel
|
|
43
52
|
# C:/Users/hallong/Documents/maya/xxxx/scripts/usersetup.mel
|
|
44
|
-
|
|
53
|
+
usersetup_mel_paths = [
|
|
45
54
|
os.path.join(self.api.local_script_path, "usersetup.mel"),
|
|
46
55
|
os.path.join(self.api.user_script_path, "usersetup.mel"),
|
|
47
|
-
]
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
56
|
+
]
|
|
57
|
+
|
|
58
|
+
for usersetup_mel in usersetup_mel_paths:
|
|
59
|
+
if os.path.exists(usersetup_mel) and check_virus_file_by_signature(usersetup_mel):
|
|
60
|
+
self.report_issue(usersetup_mel)
|
|
61
|
+
self.api.add_infected_file(usersetup_mel)
|
|
52
62
|
|
|
53
63
|
def collect_script_jobs(self):
|
|
54
64
|
"""Collect all script jobs related to the virus."""
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "maya_umbrella"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.10.0"
|
|
4
4
|
description = "Check and fix maya virus."
|
|
5
5
|
homepage = "https://github.com/loonghao/maya_umbrella"
|
|
6
6
|
repository = "https://github.com/loonghao/maya_umbrella"
|
|
@@ -36,7 +36,7 @@ nox = { version = "^2024.3.2", python = ">=3.8.1,<3.11" }
|
|
|
36
36
|
|
|
37
37
|
[tool.commitizen]
|
|
38
38
|
name = "cz_conventional_commits"
|
|
39
|
-
version = "0.
|
|
39
|
+
version = "0.10.0"
|
|
40
40
|
tag_format = "v$version"
|
|
41
41
|
version_files = [
|
|
42
42
|
"pyproject.toml:version",
|
|
@@ -134,6 +134,7 @@ exclude = [
|
|
|
134
134
|
line-length = 120
|
|
135
135
|
|
|
136
136
|
[tool.ruff.lint]
|
|
137
|
+
fixable = ["ALL"]
|
|
137
138
|
extend-select = [
|
|
138
139
|
"Q",
|
|
139
140
|
"RUF100",
|
|
@@ -144,7 +145,6 @@ extend-select = [
|
|
|
144
145
|
"DTZ005", # https://docs.astral.sh/ruff/rules/call-datetime-now-without-tzinfo/
|
|
145
146
|
] # add "T" to disallow prints
|
|
146
147
|
flake8-quotes = { inline-quotes = "double", multiline-quotes = "double" }
|
|
147
|
-
mccabe = { max-complexity = 14 }
|
|
148
148
|
ignore = [
|
|
149
149
|
"I001",
|
|
150
150
|
"D107", # ignore missing docstring in __init__ methods
|
|
@@ -160,6 +160,9 @@ ignore = [
|
|
|
160
160
|
"UP025",
|
|
161
161
|
]
|
|
162
162
|
|
|
163
|
+
[tool.ruff.lint.mccabe]
|
|
164
|
+
max-complexity = 45
|
|
165
|
+
|
|
163
166
|
[tool.ruff.lint.pydocstyle]
|
|
164
167
|
convention = "google"
|
|
165
168
|
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "0.8.0"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|