-
Notifications
You must be signed in to change notification settings - Fork 0
/
Updater.py
225 lines (192 loc) · 7.67 KB
/
Updater.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
import datetime
import os
import zipfile
import io
import json
import requests
import shutil
import bpy
bl_info = {"version": (1, 3, 1)}
class GithubEngine:
def __init__(self):
self._api_url = 'https://api.github.com'
self._token = None
self._user = None
self._repo = None
self._current_version = None
self._latest_version = None
self._response = None
self._update_date = None
def clear_state(self):
self._token = None
self._user = None
self._repo = None
self._current_version = None
self._latest_version = None
self._response = None
self._update_date = None
@property
def token(self):
return self._token
@token.setter
def token(self, value):
if value is None:
self._token = None
else:
self._token = str(value)
@property
def user(self):
return self._user
@user.setter
def user(self, value):
self._user = str(value)
@property
def repo(self):
return self._repo
@repo.setter
def repo(self, value):
self._repo = str(value)
@property
def api_url(self):
return self._api_url
@property
def update_date(self):
return self._update_date
@api_url.setter
def api_url(self, value):
if not self.check_is_url(value):
raise ValueError("Not a valid URL: " + value)
self._api_url = value
@staticmethod
def check_is_url(url):
if not ("http://" in url or "https://" in url):
return False
if "." not in url:
return False
return True
def delete_file_in_folder(self):
"""
The function `delete_file_in_folder` deletes all files inside a specified folder.
"""
folder_path = os.path.join(
os.path.dirname(__file__), "..", f"{self.repo}-main")
directories = [item for item in os.listdir(
folder_path) if os.path.isdir(os.path.join(folder_path, item))]
try:
for directory_name in directories:
if directory_name.startswith(f"{self.user}"):
target_folder = os.path.join(folder_path, directory_name)
for root, dirs, files in os.walk(target_folder):
for file in files:
file_path = os.path.join(root, file)
if file == "version_info.json":
os.remove(file_path)
print(f"Files inside {folder_path} deleted successfully.")
except FileNotFoundError as e:
print(f"Error deleting files in {folder_path}: {e}")
def delete_folder(self):
"""
The `delete_folder` function deletes a specific folder and its contents within a given
repository.
"""
folder_path = os.path.join(
os.path.dirname(__file__), "..", f"{self.repo}-main")
directories = [item for item in os.listdir(
folder_path) if os.path.isdir(os.path.join(folder_path, item))]
try:
for directory_name in directories:
if directory_name.startswith(f"{self.user}"):
target_folder = os.path.join(folder_path, directory_name)
shutil.rmtree(target_folder)
print(f"Folder {folder_path} deleted successfully.")
except FileNotFoundError as e:
print(f"Error deleting folder {folder_path}: {e}")
def extract_folder(self):
"""
The function `extract_folder` extracts the contents of a specific folder from a given repository
and copies them to the base path.
"""
folder_path = os.path.join(
os.path.dirname(__file__), "..", f"{self.repo}-main")
directories = [item for item in os.listdir(
folder_path) if os.path.isdir(os.path.join(folder_path, item))]
# Find the specific folder that starts with username
target_folder = None
for directory_name in directories:
if directory_name.startswith(f"{self.user}"):
target_folder = os.path.join(folder_path, directory_name)
break
if target_folder is not None:
destination_folder = folder_path
print(f"Found target folder: {target_folder}")
for item in os.listdir(target_folder):
source_item_path = os.path.join(target_folder, item)
destination_item_path = os.path.join(destination_folder, item)
if os.path.isfile(source_item_path):
shutil.copy2(source_item_path, destination_item_path)
elif os.path.isdir(source_item_path):
shutil.copytree(source_item_path, destination_item_path)
print("Contents extracted to base path.")
else:
print("Target folder not found.")
@bpy.app.handlers.persistent
def check_for_updates(self):
"""
The above function checks for updates of a Blender add-on by making a request to a specified API
endpoint and compares the latest version with the current version of the add-on.
:return: The code is returning the latest version of the addon, the current version of the
addon, and the update date.
"""
update_url = f"{self.api_url}/repos/{self.user}/{self.repo}/releases/latest"
addon_path = os.path.dirname(__file__)
if self._current_version is None:
raise ValueError("current_version not yet defined")
try:
response = requests.get(update_url)
response.raise_for_status()
except requests.exceptions.RequestException as e:
print("Error checking for updates:", e)
if response.status_code != 200:
print("Response content:", response.content)
return None
data = json.loads(response.text)
date = datetime.datetime.now()
latest_version = data["tag_name"]
current_version = f"{bl_info['version'][0]}.{bl_info['version'][1]}.{bl_info['version'][2]}"
addon_version = {
"current_version": current_version,
"latest_version": latest_version,
"update_date": str(date),
}
json_file_path = os.path.join(addon_path, "version_info.json")
try:
with open(json_file_path, 'w') as json_file:
json.dump(addon_version, json_file, indent=1)
except zipfile.BadZipFile as e:
print("Error extracting zip file:", e)
return None
if self._latest_version != self._current_version:
return self._latest_version
return self._current_version, self._update_date
@bpy.app.handlers.persistent
def update(self):
"""
The `update` function downloads a zip file from a specified URL, extracts its contents, and
performs some additional operations on the extracted files.
:return: None if there is an error extracting the zip file.
"""
zipball_url = f"{self.api_url}/repos/{self.user}/{self.repo}/zipball/{self.check_for_updates()}"
response = requests.get(zipball_url)
self._response = response
addon_path = os.path.dirname(__file__)
zip_data = io.BytesIO(response.content)
try:
with zipfile.ZipFile(zip_data, 'r') as zip_ref:
zip_ref.extractall(addon_path)
self.extract_folder()
self.delete_file_in_folder()
self.delete_folder()
except zipfile.BadZipFile as e:
print("Error extracting zip file:", e)
return None
engine = GithubEngine()