import locale import os import re import shutil import subprocess import tarfile import time import zipfile from pathlib import Path from subprocess import DEVNULL, PIPE, STDOUT from urllib.request import urlopen from PyQt5.QtCore import QThread, pyqtSignal from _platform import get_platform if get_platform() == 'Windows': from subprocess import CREATE_NO_WINDOW class BuildLoader(QThread): finished = pyqtSignal('PyQt_PyObject') block_abortion = pyqtSignal() progress_changed = pyqtSignal( 'PyQt_PyObject', 'PyQt_PyObject', 'PyQt_PyObject') def __init__(self, parent, url, strptime): QThread.__init__(self) self.parent = parent self.url = url self.strptime = strptime self.root_folder = self.parent.settings.value('root_folder') self.is_running = False self.platform = get_platform() def run(self): self.is_running = True blender_zip = urlopen(self.url) size = blender_zip.info()['Content-Length'] temp_path = os.path.join(self.root_folder, "temp") path = os.path.join(temp_path, self.url.split('/', -1)[-1]) # Create temp directory if not os.path.isdir(temp_path): os.makedirs(temp_path) # Download with open(path, 'wb') as file: while True: chunk = blender_zip.read(16 * 1024) if not chunk: break file.write(chunk) progress = os.stat(path).st_size / int(size) self.progress_changed.emit( progress, progress * 0.5, "Downloading: %p%") if not self.is_running: file.close() if os.path.isdir(temp_path): shutil.rmtree(temp_path) self.finished.emit(None) return # Show extraction progress at 0 self.progress_changed.emit(0, 0, "Extracting: %p%") # Extract if self.platform == 'Windows': zf = zipfile.ZipFile(path) version = zf.infolist()[0].filename.split('/')[0] uncompress_size = sum((file.file_size for file in zf.infolist())) extracted_size = 0 for file in zf.infolist(): zf.extract(file, self.root_folder) extracted_size += file.file_size progress = extracted_size / uncompress_size self.progress_changed.emit( progress, progress * 0.5 + 0.5, "Extracting: %p%") if not self.is_running: zf.close() shutil.rmtree(os.path.join(self.root_folder, version)) if os.path.isdir(temp_path): shutil.rmtree(temp_path) self.finished.emit(None) return zf.close() elif self.platform == 'Linux': tar = tarfile.open(path) version = tar.getnames()[0].split('/')[0] uncompress_size = sum((member.size for member in tar.getmembers())) extracted_size = 0 for member in tar.getmembers(): tar.extract(member, path=self.root_folder) extracted_size += member.size progress = extracted_size / uncompress_size self.progress_changed.emit( progress, progress * 0.5 + 0.5, "Extracting: %p%") if not self.is_running: tar.close() shutil.rmtree(os.path.join(self.root_folder, version)) if os.path.isdir(temp_path): shutil.rmtree(temp_path) self.finished.emit(None) return tar.close() self.block_abortion.emit() self.progress_changed.emit(0, 0, "Finishing...") # Delete temp folder if os.path.isdir(temp_path): shutil.rmtree(temp_path) if self.platform == 'Windows': locale.setlocale(locale.LC_ALL, 'eng_usa') elif self.platform == 'Linux': locale.setlocale(locale.LC_ALL, 'en_US.UTF-8') # Make nice name for dir git = self.url.split('-',)[-2] nice_name = "Git-%s-%s" % \ (git, time.strftime("%d-%b-%H-%M", self.strptime)) source_path = Path(os.path.join(self.root_folder, version)) target_path = Path(os.path.join(self.root_folder, nice_name)) source_path.rename(target_path) # Register .blend extension if self.parent.settings.value('is_register_blend', type=bool): if self.platform == 'Windows': b3d_exe = target_path / "blender.exe" subprocess.call([str(b3d_exe), "-r"], creationflags=CREATE_NO_WINDOW, shell=True, stdout=PIPE, stderr=STDOUT, stdin=DEVNULL) elif self.platform == 'Linux': pass # TODO Linux has different file association method? # b3d_exe = target_path / "blender" # subprocess.call([str(b3d_exe), "-r"], # shell=True, stdout=PIPE, stderr=STDOUT, stdin=DEVNULL) self.finished.emit(nice_name) def stop(self): self.is_running = False