mirror of
https://github.com/ynput/ayon-core.git
synced 2025-12-24 12:54:40 +01:00
add update dialog
This commit is contained in:
parent
580e8ade0e
commit
df310da141
6 changed files with 274 additions and 3 deletions
|
|
@ -31,8 +31,31 @@ def open_dialog():
|
|||
return d.result()
|
||||
|
||||
|
||||
def open_update_window(openpype_version):
|
||||
"""Open update window."""
|
||||
if os.getenv("OPENPYPE_HEADLESS_MODE"):
|
||||
print("!!! Can't open dialog in headless mode. Exiting.")
|
||||
sys.exit(1)
|
||||
from Qt import QtWidgets, QtCore
|
||||
from .update_window import UpdateWindow
|
||||
|
||||
scale_attr = getattr(QtCore.Qt, "AA_EnableHighDpiScaling", None)
|
||||
if scale_attr is not None:
|
||||
QtWidgets.QApplication.setAttribute(scale_attr)
|
||||
|
||||
app = QtWidgets.QApplication(sys.argv)
|
||||
|
||||
d = UpdateWindow(version=openpype_version)
|
||||
d.open()
|
||||
|
||||
app.exec_()
|
||||
version_path = d.get_version_path()
|
||||
return version_path
|
||||
|
||||
|
||||
__all__ = [
|
||||
"BootstrapRepos",
|
||||
"open_dialog",
|
||||
"open_update_window",
|
||||
"version"
|
||||
]
|
||||
|
|
|
|||
|
|
@ -966,6 +966,7 @@ class BootstrapRepos:
|
|||
|
||||
# test if destination directory already exist, if so lets delete it.
|
||||
if destination.exists() and force:
|
||||
self._print("removing existing directory")
|
||||
try:
|
||||
shutil.rmtree(destination)
|
||||
except OSError as e:
|
||||
|
|
@ -975,6 +976,7 @@ class BootstrapRepos:
|
|||
raise OpenPypeVersionIOError(
|
||||
f"cannot remove existing {destination}") from e
|
||||
elif destination.exists() and not force:
|
||||
self._print("destination directory already exists")
|
||||
raise OpenPypeVersionExists(f"{destination} already exist.")
|
||||
else:
|
||||
# create destination parent directories even if they don't exist.
|
||||
|
|
@ -984,6 +986,7 @@ class BootstrapRepos:
|
|||
if openpype_version.path.is_dir():
|
||||
# create zip inside temporary directory.
|
||||
self._print("Creating zip from directory ...")
|
||||
self._progress_callback(0)
|
||||
with tempfile.TemporaryDirectory() as temp_dir:
|
||||
temp_zip = \
|
||||
Path(temp_dir) / f"openpype-v{openpype_version}.zip"
|
||||
|
|
@ -1009,13 +1012,16 @@ class BootstrapRepos:
|
|||
raise OpenPypeVersionInvalid("Invalid file format")
|
||||
|
||||
if not self.is_inside_user_data(openpype_version.path):
|
||||
self._progress_callback(35)
|
||||
openpype_version.path = self._copy_zip(
|
||||
openpype_version.path, destination)
|
||||
|
||||
# extract zip there
|
||||
self._print("extracting zip to destination ...")
|
||||
with ZipFile(openpype_version.path, "r") as zip_ref:
|
||||
self._progress_callback(75)
|
||||
zip_ref.extractall(destination)
|
||||
self._progress_callback(100)
|
||||
|
||||
return destination
|
||||
|
||||
|
|
|
|||
61
igniter/update_thread.py
Normal file
61
igniter/update_thread.py
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""Working thread for update."""
|
||||
from Qt.QtCore import QThread, Signal, QObject # noqa
|
||||
|
||||
from .bootstrap_repos import (
|
||||
BootstrapRepos,
|
||||
OpenPypeVersion
|
||||
)
|
||||
|
||||
|
||||
class UpdateThread(QThread):
|
||||
"""Install Worker thread.
|
||||
|
||||
This class takes care of finding OpenPype version on user entered path
|
||||
(or loading this path from database). If nothing is entered by user,
|
||||
OpenPype will create its zip files from repositories that comes with it.
|
||||
|
||||
If path contains plain repositories, they are zipped and installed to
|
||||
user data dir.
|
||||
|
||||
"""
|
||||
progress = Signal(int)
|
||||
message = Signal((str, bool))
|
||||
|
||||
def __init__(self, parent=None):
|
||||
self._result = None
|
||||
self._openpype_version = None
|
||||
QThread.__init__(self, parent)
|
||||
|
||||
def set_version(self, openpype_version: OpenPypeVersion):
|
||||
self._openpype_version = openpype_version
|
||||
|
||||
def result(self):
|
||||
"""Result of finished installation."""
|
||||
return self._result
|
||||
|
||||
def _set_result(self, value):
|
||||
if self._result is not None:
|
||||
raise AssertionError("BUG: Result was set more than once!")
|
||||
self._result = value
|
||||
|
||||
def run(self):
|
||||
"""Thread entry point.
|
||||
|
||||
Using :class:`BootstrapRepos` to either install OpenPype as zip files
|
||||
or copy them from location specified by user or retrieved from
|
||||
database.
|
||||
"""
|
||||
bs = BootstrapRepos(
|
||||
progress_callback=self.set_progress, message=self.message)
|
||||
version_path = bs.install_version(self._openpype_version)
|
||||
self._set_result(version_path)
|
||||
|
||||
def set_progress(self, progress: int) -> None:
|
||||
"""Helper to set progress bar.
|
||||
|
||||
Args:
|
||||
progress (int): Progress in percents.
|
||||
|
||||
"""
|
||||
self.progress.emit(progress)
|
||||
173
igniter/update_window.py
Normal file
173
igniter/update_window.py
Normal file
|
|
@ -0,0 +1,173 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""Progress window to show when OpenPype is updating/installing locally."""
|
||||
import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from .update_thread import UpdateThread
|
||||
from Qt import QtCore, QtGui, QtWidgets # noqa
|
||||
from .bootstrap_repos import OpenPypeVersion
|
||||
|
||||
|
||||
def load_stylesheet(path: str = None) -> str:
|
||||
"""Load css style sheet.
|
||||
|
||||
Args:
|
||||
path (str, optional): Path to stylesheet. If none, `stylesheet.css` from
|
||||
current package's path is used.
|
||||
Returns:
|
||||
str: content of the stylesheet
|
||||
|
||||
"""
|
||||
if path:
|
||||
stylesheet_path = Path(path)
|
||||
else:
|
||||
stylesheet_path = Path(os.path.dirname(__file__)) / "stylesheet.css"
|
||||
|
||||
return stylesheet_path.read_text()
|
||||
|
||||
|
||||
class NiceProgressBar(QtWidgets.QProgressBar):
|
||||
def __init__(self, parent=None):
|
||||
super(NiceProgressBar, self).__init__(parent)
|
||||
self._real_value = 0
|
||||
|
||||
def setValue(self, value):
|
||||
self._real_value = value
|
||||
if value != 0 and value < 11:
|
||||
value = 11
|
||||
|
||||
super(NiceProgressBar, self).setValue(value)
|
||||
|
||||
def value(self):
|
||||
return self._real_value
|
||||
|
||||
def text(self):
|
||||
return "{} %".format(self._real_value)
|
||||
|
||||
|
||||
class UpdateWindow(QtWidgets.QDialog):
|
||||
"""OpenPype update window."""
|
||||
|
||||
_width = 500
|
||||
_height = 100
|
||||
|
||||
def __init__(self, version: OpenPypeVersion, parent=None):
|
||||
super(UpdateWindow, self).__init__(parent)
|
||||
self._openpype_version = version
|
||||
self._result_version_path = None
|
||||
|
||||
self.setWindowTitle(
|
||||
f"OpenPype is updating ..."
|
||||
)
|
||||
self.setModal(True)
|
||||
self.setWindowFlags(
|
||||
QtCore.Qt.WindowMinimizeButtonHint
|
||||
)
|
||||
|
||||
current_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
roboto_font_path = os.path.join(current_dir, "RobotoMono-Regular.ttf")
|
||||
poppins_font_path = os.path.join(current_dir, "Poppins")
|
||||
icon_path = os.path.join(current_dir, "openpype_icon.png")
|
||||
|
||||
# Install roboto font
|
||||
QtGui.QFontDatabase.addApplicationFont(roboto_font_path)
|
||||
for filename in os.listdir(poppins_font_path):
|
||||
if os.path.splitext(filename)[1] == ".ttf":
|
||||
QtGui.QFontDatabase.addApplicationFont(filename)
|
||||
|
||||
# Load logo
|
||||
pixmap_openpype_logo = QtGui.QPixmap(icon_path)
|
||||
# Set logo as icon of window
|
||||
self.setWindowIcon(QtGui.QIcon(pixmap_openpype_logo))
|
||||
|
||||
self._pixmap_openpype_logo = pixmap_openpype_logo
|
||||
|
||||
self._update_thread = None
|
||||
|
||||
self.resize(QtCore.QSize(self._width, self._height))
|
||||
self._init_ui()
|
||||
|
||||
# Set stylesheet
|
||||
self.setStyleSheet(load_stylesheet())
|
||||
self._run_update()
|
||||
|
||||
def _init_ui(self):
|
||||
|
||||
# Main info
|
||||
# --------------------------------------------------------------------
|
||||
main_label = QtWidgets.QLabel(
|
||||
f"<b>OpenPype</b> is updating to {self._openpype_version}", self)
|
||||
main_label.setWordWrap(True)
|
||||
main_label.setObjectName("MainLabel")
|
||||
|
||||
# Progress bar
|
||||
# --------------------------------------------------------------------
|
||||
progress_bar = NiceProgressBar(self)
|
||||
progress_bar.setAlignment(QtCore.Qt.AlignCenter)
|
||||
progress_bar.setTextVisible(False)
|
||||
|
||||
# add all to main
|
||||
main = QtWidgets.QVBoxLayout(self)
|
||||
main.addSpacing(15)
|
||||
main.addWidget(main_label, 0)
|
||||
main.addSpacing(15)
|
||||
main.addWidget(progress_bar, 0)
|
||||
main.addSpacing(15)
|
||||
|
||||
self._progress_bar = progress_bar
|
||||
|
||||
def _run_update(self):
|
||||
"""Start install process.
|
||||
|
||||
This will once again validate entered path and mongo if ok, start
|
||||
working thread that will do actual job.
|
||||
"""
|
||||
# Check if install thread is not already running
|
||||
if self._update_thread and self._update_thread.isRunning():
|
||||
return
|
||||
self._progress_bar.setRange(0, 0)
|
||||
update_thread = UpdateThread(self)
|
||||
update_thread.set_version(self._openpype_version)
|
||||
update_thread.message.connect(self.update_console)
|
||||
update_thread.progress.connect(self._update_progress)
|
||||
update_thread.finished.connect(self._installation_finished)
|
||||
|
||||
self._update_thread = update_thread
|
||||
|
||||
update_thread.start()
|
||||
|
||||
def get_version_path(self):
|
||||
return self._result_version_path
|
||||
|
||||
def _installation_finished(self):
|
||||
status = self._update_thread.result()
|
||||
self._result_version_path = status
|
||||
self._progress_bar.setRange(0, 1)
|
||||
self._update_progress(100)
|
||||
QtWidgets.QApplication.processEvents()
|
||||
self.done(0)
|
||||
|
||||
def _update_progress(self, progress: int):
|
||||
# not updating progress as we are not able to determine it
|
||||
# correctly now. Progress bar is set to un-deterministic mode
|
||||
# until we are able to get progress in better way.
|
||||
"""
|
||||
self._progress_bar.setRange(0, 0)
|
||||
self._progress_bar.setValue(progress)
|
||||
text_visible = self._progress_bar.isTextVisible()
|
||||
if progress == 0:
|
||||
if text_visible:
|
||||
self._progress_bar.setTextVisible(False)
|
||||
elif not text_visible:
|
||||
self._progress_bar.setTextVisible(True)
|
||||
"""
|
||||
return
|
||||
|
||||
def update_console(self, msg: str, error: bool = False) -> None:
|
||||
"""Display message in console.
|
||||
|
||||
Args:
|
||||
msg (str): message.
|
||||
error (bool): if True, print it red.
|
||||
"""
|
||||
print(msg)
|
||||
|
|
@ -18,7 +18,7 @@ from .pype_commands import PypeCommands
|
|||
@click.option("--list-versions", is_flag=True, expose_value=False,
|
||||
help=("list all detected versions. Use With `--use-staging "
|
||||
"to list staging versions."))
|
||||
@click.option("--validate-version",
|
||||
@click.option("--validate-version", expose_value=False,
|
||||
help="validate given version integrity")
|
||||
def main(ctx):
|
||||
"""Pype is main command serving as entry point to pipeline system.
|
||||
|
|
|
|||
12
start.py
12
start.py
|
|
@ -610,8 +610,16 @@ def _find_frozen_openpype(use_version: str = None,
|
|||
|
||||
if not is_inside:
|
||||
# install latest version to user data dir
|
||||
version_path = bootstrap.install_version(
|
||||
openpype_version, force=True)
|
||||
if not os.getenv("OPENPYPE_HEADLESS"):
|
||||
import igniter
|
||||
version_path = igniter.open_update_window(openpype_version)
|
||||
else:
|
||||
version_path = bootstrap.install_version(
|
||||
openpype_version, force=True)
|
||||
|
||||
openpype_version.path = version_path
|
||||
_initialize_environment(openpype_version)
|
||||
return openpype_version.path
|
||||
|
||||
if openpype_version.path.is_file():
|
||||
_print(">>> Extracting zip file ...")
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue