Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Show message about missing requirements #34

Merged
merged 3 commits into from
Aug 16, 2023
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions common/ayon_common/startup/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
"""Helpers for startup script."""
import os
import json
import subprocess
import tempfile

from ayon_common.utils import get_ayon_launch_args


def shot_startup_error(title, message):
iLLiCiTiT marked this conversation as resolved.
Show resolved Hide resolved
"""Show startup error message.

This will trigger a subprocess with UI message dialog.

Args:
title (str): Message title.
message (str): Message content.
"""

current_dir = os.path.dirname(os.path.abspath(__file__))
ui_dir = os.path.join(current_dir, "ui")
script_path = os.path.join(ui_dir, "startup_error.py")
with tempfile.NamedTemporaryFile(
suffix=".json", delete=False
) as tmp:
filepath = tmp.name

with open(filepath, "w") as stream:
json.dump({"title": title, "message": message}, stream)

args = get_ayon_launch_args(
script_path, "--skip-bootstrap", filepath
)
try:
subprocess.call(args)
finally:
os.remove(filepath)
120 changes: 120 additions & 0 deletions common/ayon_common/startup/ui/startup_error.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
import sys
import json

from qtpy import QtWidgets, QtGui

from ayon_common.resources import (
get_icon_path,
load_stylesheet,
)
from ayon_common.ui_utils import get_qt_app


class MessageWindow(QtWidgets.QDialog):
default_width = 410
default_height = 170

def __init__(self, title, message, parent=None):
super().__init__(parent)

icon_path = get_icon_path()
icon = QtGui.QIcon(icon_path)
self.setWindowIcon(icon)
self.setWindowTitle(title)

self._first_show = True

body_widget = QtWidgets.QWidget(self)

icon_side = QtWidgets.QWidget(body_widget)
icon_label = QtWidgets.QLabel(icon_side)
icon_side_layout = QtWidgets.QVBoxLayout(icon_side)
icon_side_layout.setContentsMargins(3, 3, 3, 3)
icon_side_layout.addWidget(icon_label, 0)
icon_side_layout.addStretch(1)

info_widget = QtWidgets.QWidget(body_widget)
info_label = QtWidgets.QLabel(message, info_widget)
info_label.setWordWrap(True)

info_layout = QtWidgets.QVBoxLayout(info_widget)
info_layout.setContentsMargins(0, 0, 0, 0)
info_layout.addWidget(info_label, 0)
info_layout.addStretch(1)

body_layout = QtWidgets.QHBoxLayout(body_widget)
body_layout.setContentsMargins(0, 0, 0, 0)
body_layout.addWidget(icon_side, 0)
body_layout.addWidget(info_widget, 1)

btns_widget = QtWidgets.QWidget(self)
confirm_btn = QtWidgets.QPushButton("Close", btns_widget)

btns_layout = QtWidgets.QHBoxLayout(btns_widget)
btns_layout.setContentsMargins(0, 0, 0, 0)
btns_layout.addStretch(1)
btns_layout.addWidget(confirm_btn, 0)

main_layout = QtWidgets.QVBoxLayout(self)
main_layout.addWidget(body_widget, 1)
main_layout.addWidget(btns_widget, 0)

confirm_btn.clicked.connect(self._on_confirm_click)

self._icon_label = icon_label
self._confirm_btn = confirm_btn

def showEvent(self, event):
super().showEvent(event)
if self._first_show:
self._first_show = False
self._on_first_show()
self._recalculate_sizes()

def resizeEvent(self, event):
super().resizeEvent(event)
self._recalculate_sizes()

def _update_icon(self):
style = self.style()
size = style.pixelMetric(
QtWidgets.QStyle.PM_MessageBoxIconSize, None, self)
icon = style.standardIcon(
QtWidgets.QStyle.SP_MessageBoxCritical, None, self)

self._icon_label.setPixmap(icon.pixmap(size, size))

def _recalculate_sizes(self):
hint = self._confirm_btn.sizeHint()
new_width = max((hint.width(), hint.height() * 3))
self._confirm_btn.setMinimumWidth(new_width)
self._update_icon()

def _on_first_show(self):
self.setStyleSheet(load_stylesheet())
self.resize(self.default_width, self.default_height)

def _on_confirm_click(self):
self.accept()
self.close()


def main():
"""Show message that server does not have set bundle to use.

It is possible to pass url as argument to show it in the message. To use
this feature, pass `--url <url>` as argument to this script.
"""

filepath = sys.argv[-1]
with open(filepath, "r") as stream:
data = json.load(stream)

app = get_qt_app()
window = MessageWindow(data["title"], data["message"])
window.show()
app.exec_()


if __name__ == "__main__":
main()
44 changes: 42 additions & 2 deletions start.py
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@ def _print(message: str):
)

from ayon_common.utils import store_current_executable_info
from ayon_common.startup import shot_startup_error


def set_global_environments() -> None:
Expand Down Expand Up @@ -381,6 +382,38 @@ def boot():
store_current_executable_info()


def _on_main_addon_missing():
if HEADLESS_MODE_ENABLED:
raise RuntimeError("Failed to import required OpenPype addon.")
shot_startup_error(
"Missing OpenPype addon",
(
"AYON-launcher requires OpenPype addon to be able to start."
"<br/><br/>Please contact your administrator"
" to resolve the issue."
)
)
sys.exit(1)


def _on_main_addon_import_error():
if HEADLESS_MODE_ENABLED:
raise RuntimeError(
"Failed to import OpenPype addon. Probably because"
" of missing or incompatible dependency package"
)
shot_startup_error(
"Incompatible Dependency package",
(
"Dependency package is missing or incompatible with available"
" addons."
"<br/><br/>Please contact your administrator"
" to resolve the issue."
)
)
sys.exit(1)


def main_cli():
"""Main startup logic.

Expand All @@ -389,8 +422,15 @@ def main_cli():
contains more logic than it should.
"""

from openpype import cli
from openpype import PACKAGE_DIR
try:
from openpype import PACKAGE_DIR
except ImportError:
_on_main_addon_missing()

try:
from openpype import cli
except ImportError:
_on_main_addon_import_error()

python_path = os.getenv("PYTHONPATH", "")
split_paths = python_path.split(os.pathsep)
Expand Down