From 4fa47cbe019e220a31076c258b8f6fb5f8218230 Mon Sep 17 00:00:00 2001 From: Ondrej Samohel Date: Fri, 5 Mar 2021 17:06:39 +0100 Subject: [PATCH] streamlined UI --- igniter/__init__.py | 16 ++- igniter/__main__.py | 19 ++- igniter/bootstrap_repos.py | 14 +- igniter/install_dialog.py | 263 +++++++++++++++++++++---------------- igniter/install_thread.py | 75 ++++++++--- igniter/tools.py | 58 ++++---- start.py | 18 ++- 7 files changed, 300 insertions(+), 163 deletions(-) diff --git a/igniter/__init__.py b/igniter/__init__.py index 6fce75e95a..12f3b49457 100644 --- a/igniter/__init__.py +++ b/igniter/__init__.py @@ -2,18 +2,30 @@ """Open install dialog.""" import sys -from Qt import QtWidgets +from Qt import QtWidgets # noqa +from Qt.QtCore import Signal # noqa from .install_dialog import InstallDialog from .bootstrap_repos import BootstrapRepos +RESULT = 0 + + +def get_result(res: int): + """Sets result returned from dialog.""" + global RESULT + RESULT = res + + def run(): """Show Igniter dialog.""" app = QtWidgets.QApplication(sys.argv) d = InstallDialog() + d.finished.connect(get_result) d.show() - sys.exit(app.exec_()) + app.exec_() + return RESULT __all__ = [ diff --git a/igniter/__main__.py b/igniter/__main__.py index adabb02357..d56cc893a0 100644 --- a/igniter/__main__.py +++ b/igniter/__main__.py @@ -2,11 +2,26 @@ """Open install dialog.""" import sys -from Qt import QtWidgets +from Qt import QtWidgets # noqa +from Qt.QtCore import Signal # noqa from .install_dialog import InstallDialog + +RESULT = 0 + + +def get_result(res: int): + """Sets result returned from dialog.""" + global RESULT + RESULT = res + + app = QtWidgets.QApplication(sys.argv) + d = InstallDialog() +d.finished.connect(get_result) d.show() -sys.exit(app.exec_()) +app.exec_() +print(RESULT) +sys.exit(RESULT) diff --git a/igniter/bootstrap_repos.py b/igniter/bootstrap_repos.py index da796b3e74..ccf40bfafe 100644 --- a/igniter/bootstrap_repos.py +++ b/igniter/bootstrap_repos.py @@ -456,6 +456,10 @@ class BootstrapRepos: self._progress_callback(int(progress)) arc_name = file.relative_to(frozen_root.parent) + # we need to replace first part of path which starts with + # something like `exe.win/linux....` with `pype` as this + # is expected by Pype in zip archive. + arc_name = Path("pype").joinpath(*arc_name.parts[1:]) zip_file.write(file, arc_name) destination = self._move_zip_to_data_dir(temp_zip) @@ -719,7 +723,7 @@ class BootstrapRepos: # either "live" Pype repository, or multiple zip files or even # multiple pype version directories. This process looks into zip # files and directories and tries to parse `version.py` file. - versions = self.find_pype(pype_path) + versions = self.find_pype(pype_path, include_zips=True) if versions: self._print(f"found Pype in [ {pype_path} ]") self._print(f"latest version found is [ {versions[-1]} ]") @@ -890,15 +894,17 @@ class BootstrapRepos: try: # copy file to destination self._print("Copying zip to destination ...") + _destination_zip = destination.parent / pype_version.path.name copyfile( pype_version.path.as_posix(), - destination.parent.as_posix()) + _destination_zip.as_posix()) except OSError as e: self._print( "cannot copy version to user data directory", LOG_ERROR, exc_info=True) - raise PypeVersionIOError( - "can't copy version to destination") from e + raise PypeVersionIOError(( + f"can't copy version {pype_version.path.as_posix()} " + f"to destination {destination.parent.as_posix()}")) from e # extract zip there self._print("extracting zip to destination ...") diff --git a/igniter/install_dialog.py b/igniter/install_dialog.py index 561b17408f..0431a857c0 100644 --- a/igniter/install_dialog.py +++ b/igniter/install_dialog.py @@ -5,6 +5,7 @@ import sys from Qt import QtCore, QtGui, QtWidgets # noqa from Qt.QtGui import QValidator # noqa +from Qt.QtCore import QTimer # noqa from .install_thread import InstallThread from .tools import ( @@ -35,7 +36,7 @@ class InstallDialog(QtWidgets.QDialog): """Main Igniter dialog window.""" _size_w = 400 _size_h = 600 - path = None + path = "" _controls_disabled = False def __init__(self, parent=None): @@ -75,6 +76,7 @@ class InstallDialog(QtWidgets.QDialog): os.path.join( os.path.dirname(__file__), 'RobotoMono-Regular.ttf') ) + self._pype_run_ready = False self._init_ui() @@ -93,7 +95,7 @@ class InstallDialog(QtWidgets.QDialog): """Welcome to Pype

We've detected Pype is not configured yet. But don't worry, - this is as easy as setting one thing. + this is as easy as setting one or two things.

""") self.main_label.setWordWrap(True) @@ -103,8 +105,9 @@ class InstallDialog(QtWidgets.QDialog): # -------------------------------------------------------------------- self.pype_path_label = QtWidgets.QLabel( - """This can be either Path to studio location - or Database connection string or Pype Token. + """This is Path to studio location where Pype versions + are stored. It will be pre-filled if your mongoDB connection is + already set and your studio defined this location.

Leave it empty if you want to use Pype version that come with this installation. @@ -123,7 +126,7 @@ class InstallDialog(QtWidgets.QDialog): input_layout.setContentsMargins(0, 10, 0, 10) self.user_input = FocusHandlingLineEdit() - self.user_input.setPlaceholderText("Pype repository path or url") + self.user_input.setPlaceholderText("Path to Pype versions") self.user_input.textChanged.connect(self._path_changed) self.user_input.setStyleSheet( ("color: rgb(233, 233, 233);" @@ -152,6 +155,13 @@ class InstallDialog(QtWidgets.QDialog): # Mongo box | OK button # -------------------------------------------------------------------- + self.mongo_label = QtWidgets.QLabel( + """Enter URL for running MongoDB instance:""" + ) + + self.mongo_label.setWordWrap(True) + self.mongo_label.setStyleSheet("color: rgb(150, 150, 150);") + class MongoWidget(QtWidgets.QWidget): """Widget to input mongodb URL.""" @@ -165,8 +175,8 @@ class InstallDialog(QtWidgets.QDialog): self._mongo_input.textChanged.connect(self._mongo_changed) self._mongo_input.focusIn.connect(self._focus_in) self._mongo_input.focusOut.connect(self._focus_out) - # self._mongo_input.setValidator( - # PathValidator(self._mongo_input)) + self._mongo_input.setValidator( + MongoValidator(self._mongo_input)) self._mongo_input.setStyleSheet( ("color: rgb(233, 233, 233);" "background-color: rgb(64, 64, 64);" @@ -216,11 +226,7 @@ class InstallDialog(QtWidgets.QDialog): border: 1px solid rgb(32, 64, 32); """ ) - self.parent().ok_button.setEnabled(True) - if self.parent().path != "": - path = get_pype_path_from_db(self.parent().mongo_url) - self.parent().path = path - self.parent().user_input.setText(path) + self.parent().install_button.setEnabled(True) def set_invalid(self): """Set invalid state on mongo url input.""" @@ -232,7 +238,7 @@ class InstallDialog(QtWidgets.QDialog): border: 1px solid rgb(64, 32, 32); """ ) - self.parent().ok_button.setEnabled(False) + self.parent().install_button.setEnabled(False) def set_read_only(self, state: bool): """Set input read-only.""" @@ -275,16 +281,29 @@ class InstallDialog(QtWidgets.QDialog): pype_logo_label.setPixmap(pype_logo) pype_logo_label.setContentsMargins(10, 0, 0, 10) - self.ok_button = QtWidgets.QPushButton("OK") - self.ok_button.setStyleSheet( + # install button - - - - - - - - - - - - - - - - - - - - - - - - - - - + self.install_button = QtWidgets.QPushButton("Install") + self.install_button.setStyleSheet( ("color: rgb(64, 64, 64);" "background-color: rgb(72, 200, 150);" "padding: 0.5em;") ) - self.ok_button.setMinimumSize(64, 24) - self.ok_button.setToolTip("Save and continue") - self.ok_button.clicked.connect(self._on_ok_clicked) + self.install_button.setMinimumSize(64, 24) + self.install_button.setToolTip("Install Pype") + self.install_button.clicked.connect(self._on_ok_clicked) + # run from current button - - - - - - - - - - - - - - - - - - - - - - + self.run_button = QtWidgets.QPushButton("Run without installation") + self.run_button.setStyleSheet( + ("color: rgb(64, 64, 64);" + "background-color: rgb(200, 164, 64);" + "padding: 0.5em;") + ) + self.run_button.setMinimumSize(64, 24) + self.run_button.setToolTip("Run without installing Pype") + self.run_button.clicked.connect(self._on_run_clicked) + + # install button - - - - - - - - - - - - - - - - - - - - - - - - - - - self._exit_button = QtWidgets.QPushButton("Exit") self._exit_button.setStyleSheet( ("color: rgb(64, 64, 64);" @@ -292,14 +311,16 @@ class InstallDialog(QtWidgets.QDialog): "padding: 0.5em;") ) self._exit_button.setMinimumSize(64, 24) - self._exit_button.setToolTip("Exit without saving") + self._exit_button.setToolTip("Exit") self._exit_button.clicked.connect(self._on_exit_clicked) - bottom_layout.setContentsMargins(0, 10, 0, 0) - bottom_layout.addWidget(pype_logo_label) + bottom_layout.setContentsMargins(0, 10, 10, 0) + bottom_layout.setAlignment(QtCore.Qt.AlignVCenter) + bottom_layout.addWidget(pype_logo_label, 0, QtCore.Qt.AlignVCenter) bottom_layout.addStretch(1) - bottom_layout.addWidget(self.ok_button) - bottom_layout.addWidget(self._exit_button) + bottom_layout.addWidget(self.install_button, 0, QtCore.Qt.AlignVCenter) + bottom_layout.addWidget(self.run_button, 0, QtCore.Qt.AlignVCenter) + bottom_layout.addWidget(self._exit_button, 0, QtCore.Qt.AlignVCenter) bottom_widget.setLayout(bottom_layout) bottom_widget.setStyleSheet("background-color: rgb(32, 32, 32);") @@ -321,6 +342,7 @@ class InstallDialog(QtWidgets.QDialog): color: rgb(72, 200, 150); font-family: "Roboto Mono"; font-size: 0.5em; + border: 1px solid rgb(48, 48, 48); } QScrollBar:vertical { border: 1px solid rgb(61, 115, 97); @@ -373,22 +395,24 @@ class InstallDialog(QtWidgets.QDialog): """ ) # add all to main - main.addWidget(self.main_label) - main.addWidget(self.pype_path_label) - main.addLayout(input_layout) - main.addWidget(self._mongo) - main.addStretch(1) - main.addWidget(self._status_label) - main.addWidget(self._status_box) - main.addWidget(self._progress_bar) - main.addWidget(bottom_widget) + main.addWidget(self.main_label, 0) + main.addWidget(self.pype_path_label, 0) + main.addLayout(input_layout, 0) + main.addWidget(self.mongo_label, 0) + main.addWidget(self._mongo, 0) + + main.addWidget(self._status_label, 0) + main.addWidget(self._status_box, 1) + + main.addWidget(self._progress_bar, 0) + main.addWidget(bottom_widget, 0) + self.setLayout(main) - if not self.mongo_url: - self._mongo.setVisible(False) - else: - if self._mongo.validate_url() and len(self.path) == 0: - self._mongo.setVisible(True) - self._mongo.setReadonly(True) + + # if mongo url is ok, try to get pype path from there + if self._mongo.validate_url() and len(self.path) == 0: + self.path = get_pype_path_from_db(self.mongo_url) + self.user_input.setText(self.path) def _on_select_clicked(self): """Show directory dialog.""" @@ -408,48 +432,41 @@ class InstallDialog(QtWidgets.QDialog): filename = QtCore.QDir.toNativeSeparators(result) if os.path.isdir(filename): + self.path = filename self.user_input.setText(filename) + def _on_run_clicked(self): + valid, reason = validate_mongo_connection( + self._mongo.get_mongo_url() + ) + if not valid: + self._mongo.set_invalid() + self.update_console(f"!!! {reason}", True) + return + else: + self._mongo.set_valid() + + self.done(2) + def _on_ok_clicked(self): """Start install process. - This will once again validate entered path and if ok, start + This will once again validate entered path and mongo if ok, start working thread that will do actual job. """ - valid, reason = validate_path_string(self.path) + valid, reason = validate_mongo_connection( + self._mongo.get_mongo_url() + ) if not valid: - self.user_input.setStyleSheet( - """ - background-color: rgb(32, 19, 19); - color: rgb(255, 69, 0); - padding: 0.5em; - border: 1px solid rgb(32, 64, 32); - """ - ) - self.update_console(reason, True) + self._mongo.set_invalid() + self.update_console(f"!!! {reason}", True) return else: - self.user_input.setStyleSheet( - """ - background-color: rgb(19, 19, 19); - color: rgb(64, 230, 132); - padding: 0.5em; - border: 1px solid rgb(32, 64, 32); - """ - ) - if not self.path or not self.path.startswith("mongodb"): - valid, reason = validate_mongo_connection( - self._mongo.get_mongo_url() - ) - if not valid: - self._mongo.set_invalid() - self.update_console(f"!!! {reason}", True) - return - else: - self._mongo.set_valid() + self._mongo.set_valid() self._disable_buttons() - self._install_thread = InstallThread(self) + self._install_thread = InstallThread( + self.install_result_callback_handler, self) self._install_thread.message.connect(self.update_console) self._install_thread.progress.connect(self._update_progress) self._install_thread.finished.connect(self._enable_buttons) @@ -457,28 +474,22 @@ class InstallDialog(QtWidgets.QDialog): self._install_thread.set_mongo(self._mongo.get_mongo_url()) self._install_thread.start() + def install_result_callback_handler(self, status): + """Change button behaviour based on installation outcome.""" + self.update_console(f"--- {status}") + if status >= 0: + self.install_button.setText("Run installed Pype") + self._pype_run_ready = True + def _update_progress(self, progress: int): self._progress_bar.setValue(progress) def _on_exit_clicked(self): - self.close() + self.reject() def _path_changed(self, path: str) -> str: """Set path.""" self.path = path - if not self.path.startswith("mongodb"): - self._mongo.setVisible(True) - else: - self._mongo.setVisible(False) - - if len(self.path) < 1 and not self.mongo_url: - self._mongo.setVisible(False) - - if len(self.path) == 0 and self._mongo.validate_url(): - self._mongo.setVisible(True) - self._mongo.set_read_only(True) - else: - self._mongo.set_read_only(False) return path def update_console(self, msg: str, error: bool = False) -> None: @@ -497,15 +508,17 @@ class InstallDialog(QtWidgets.QDialog): def _disable_buttons(self): """Disable buttons so user interaction doesn't interfere.""" self._btn_select.setEnabled(False) + self.run_button.setEnabled(False) self._exit_button.setEnabled(False) - self.ok_button.setEnabled(False) + self.install_button.setEnabled(False) self._controls_disabled = True def _enable_buttons(self): """Enable buttons after operation is complete.""" self._btn_select.setEnabled(True) + self.run_button.setEnabled(True) self._exit_button.setEnabled(True) - self.ok_button.setEnabled(True) + self.install_button.setEnabled(True) self._controls_disabled = False def closeEvent(self, event): # noqa @@ -515,20 +528,26 @@ class InstallDialog(QtWidgets.QDialog): return super(InstallDialog, self).closeEvent(event) -class PathValidator(QValidator): +class MongoValidator(QValidator): """Validate mongodb url for Qt widgets.""" def __init__(self, parent=None, intermediate=False): self.parent = parent self.intermediate = intermediate - super(PathValidator, self).__init__(parent) + self._validate_lock = False + self.timer = QTimer() + self.timer.timeout.connect(self._unlock_validator) + super().__init__(parent) + + def _unlock_validator(self): + self._validate_lock = False def _return_state( - self, state: QValidator.State, reason: str, path: str): + self, state: QValidator.State, reason: str, mongo: str): """Set stylesheets and actions on parent based on state. Warning: - This will always return `QFileDialog.State.Acceptable` as + This will always return `QValidator.State.Acceptable` as anything different will stop input to `QLineEdit` """ @@ -540,7 +559,7 @@ class PathValidator(QValidator): background-color: rgb(32, 19, 19); color: rgb(255, 69, 0); padding: 0.5em; - border: 1px solid rgb(32, 64, 32); + border: 1px solid rgb(64, 32, 32); """ ) elif state == QValidator.State.Intermediate and self.intermediate: @@ -564,38 +583,62 @@ class PathValidator(QValidator): """ ) - return QValidator.State.Acceptable, path, len(path) + return QValidator.State.Acceptable, mongo, len(mongo) - def validate(self, path: str, pos: int) -> (QValidator.State, str, int): # noqa - """Validate entered path. + def validate(self, mongo: str, pos: int) -> (QValidator.State, str, int): # noqa + """Validate entered mongodb connection string. - It can be regular path - in that case we test if it does exist. - It can also be mongodb connection string. In that case we parse it - as url (it should start with `mongodb://` url schema. + As url (it should start with `mongodb://` or + `mongodb+srv:// url schema. Args: - path (str): path, connection string url or pype token. + mongo (str): connection string url. pos (int): current position. - Todo: - It can also be Pype token, binding it to Pype user account. + Returns: + (QValidator.State.Acceptable, str, int): + Indicate input state with color and always return + Acceptable state as we need to be able to edit input further. """ - if path.startswith("mongodb"): + if not mongo.startswith("mongodb"): return self._return_state( - QValidator.State.Intermediate, "", path) + QValidator.State.Invalid, "need mongodb schema", mongo) - if len(path) < 6: - return self._return_state( - QValidator.State.Intermediate, "", path) + return self._return_state( + QValidator.State.Intermediate, "", mongo) - valid, reason = validate_path_string(path) - if not valid: + +class PathValidator(MongoValidator): + """Validate mongodb url for Qt widgets.""" + + def validate(self, path: str, pos: int) -> (QValidator.State, str, int): # noqa + """Validate path to be accepted by Igniter. + + Args: + path (str): path to Pype. + pos (int): current position. + + Returns: + (QValidator.State.Acceptable, str, int): + Indicate input state with color and always return + Acceptable state as we need to be able to edit input further. + + """ + # allow empty path as that will use current version coming with + # Pype Igniter + if len(path) == 0: return self._return_state( - QValidator.State.Invalid, reason, path) - else: - return self._return_state( - QValidator.State.Acceptable, reason, path) + QValidator.State.Acceptable, "Use version with Igniter", path) + + if len(path) > 3: + valid, reason = validate_path_string(path) + if not valid: + return self._return_state( + QValidator.State.Invalid, reason, path) + else: + return self._return_state( + QValidator.State.Acceptable, reason, path) class CollapsibleWidget(QtWidgets.QWidget): @@ -688,7 +731,7 @@ class CollapsibleWidget(QtWidgets.QWidget): con_anim.setDuration(self._animation) con_anim.setStartValue(0) - con_anim.setEndValue(32) + con_anim.setEndValue(collapsed_height + content_height) if __name__ == "__main__": diff --git a/igniter/install_thread.py b/igniter/install_thread.py index 29adc36ddc..51bdc31a2d 100644 --- a/igniter/install_thread.py +++ b/igniter/install_thread.py @@ -4,13 +4,25 @@ import os import sys from pathlib import Path -from Qt.QtCore import QThread, Signal # noqa +from Qt.QtCore import QThread, Signal, QObject # noqa + +from .bootstrap_repos import ( + BootstrapRepos, + PypeVersionInvalid, + PypeVersionIOError, + PypeVersionExists, + PypeVersion +) -from .bootstrap_repos import BootstrapRepos -from .bootstrap_repos import PypeVersion from .tools import validate_mongo_connection +class InstallResult(QObject): + """Used to pass results back.""" + def __init__(self, value): + self.status = value + + class InstallThread(QThread): """Install Worker thread. @@ -24,12 +36,15 @@ class InstallThread(QThread): """ progress = Signal(int) message = Signal((str, bool)) + finished = Signal(object) - def __init__(self, parent=None): + def __init__(self, callback, parent=None,): self._mongo = None self._path = None + self.result_callback = callback QThread.__init__(self, parent) + self.finished.connect(callback) def run(self): """Thread entry point. @@ -60,6 +75,7 @@ class InstallThread(QThread): except ValueError: self.message.emit( "!!! We need MongoDB URL to proceed.", True) + self.finished.emit(InstallResult(-1)) return else: self._mongo = os.getenv("PYPE_MONGO") @@ -82,7 +98,7 @@ class InstallThread(QThread): self.message.emit("Skipping Pype install ...", False) if detected[-1].path.suffix.lower() == ".zip": bs.extract_pype(detected[-1]) - return + self.finished.emit(InstallResult(0)) if PypeVersion(version=local_version).get_main_version() == detected[-1].get_main_version(): # noqa self.message.emit(( @@ -90,26 +106,26 @@ class InstallThread(QThread): f"currently running {local_version}" ), False) self.message.emit("Skipping Pype install ...", False) - return + self.finished.emit(InstallResult(0)) self.message.emit(( "All installed versions are older then " f"currently running one {local_version}" ), False) else: - # we cannot build install package from frozen code. - # todo: we can if getattr(sys, 'frozen', False): self.message.emit("None detected.", True) - self.message.emit(("Please set path to Pype sources to " - "build installation."), False) + self.message.emit(("We will use Pype coming with " + "installer."), False) pype_version = bs.create_version_from_frozen_code() if not pype_version: self.message.emit( f"!!! Install failed - {pype_version}", True) - return + self.finished.emit(InstallResult(-1)) + self.message.emit(f"Using: {pype_version}", False) bs.install_version(pype_version) self.message.emit(f"Installed as {pype_version}", False) + self.finished.emit(InstallResult(1)) else: self.message.emit("None detected.", False) @@ -120,9 +136,15 @@ class InstallThread(QThread): if not local_pype: self.message.emit( f"!!! Install failed - {local_pype}", True) - return + self.finished.emit(InstallResult(-1)) - bs.install_version(local_pype) + try: + bs.install_version(local_pype) + except (PypeVersionExists, + PypeVersionInvalid, + PypeVersionIOError) as e: + self.message.emit(f"Installed failed", True) + self.finished.emit(InstallResult(-1)) self.message.emit(f"Installed as {local_pype}", False) else: @@ -132,25 +154,44 @@ class InstallThread(QThread): if not validate_mongo_connection(self._mongo): self.message.emit( f"!!! invalid mongo url {self._mongo}", True) - return + self.finished.emit(InstallResult(-1)) bs.registry.set_secure_item("pypeMongo", self._mongo) os.environ["PYPE_MONGO"] = self._mongo - if os.getenv("PYPE_PATH") == self._path: - ... - self.message.emit(f"processing {self._path}", True) repo_file = bs.process_entered_location(self._path) if not repo_file: self.message.emit("!!! Cannot install", True) + self.finished.emit(InstallResult(-1)) return + self.finished.emit(InstallResult(1)) + return + def set_path(self, path: str) -> None: + """Helper to set path. + + Args: + path (str): Path to set. + + """ self._path = path def set_mongo(self, mongo: str) -> None: + """Helper to set mongo url. + + Args: + mongo (str): Mongodb url. + + """ self._mongo = mongo def set_progress(self, progress: int) -> None: + """Helper to set progress bar. + + Args: + progress (int): Progress in percents. + + """ self.progress.emit(progress) diff --git a/igniter/tools.py b/igniter/tools.py index ae2ab4c586..bd9b4577a0 100644 --- a/igniter/tools.py +++ b/igniter/tools.py @@ -6,11 +6,9 @@ Functions ``compose_url()`` and ``decompose_url()`` are the same as in version is decided. """ - -import os -import uuid from typing import Dict, Union from urllib.parse import urlparse, parse_qs +from pathlib import Path import platform from pymongo import MongoClient @@ -142,13 +140,32 @@ def validate_mongo_connection(cnx: str) -> (bool, str): return True, "Connection is successful" -def validate_path_string(path: str) -> (bool, str): - """Validate string if it is acceptable by **Igniter**. - - `path` string can be either regular path, or mongodb url or Pype token. +def validate_mongo_string(mongo: str) -> (bool, str): + """Validate string if it is mongo url acceptable by **Igniter**.. Args: - path (str): String to validate. + mongo (str): String to validate. + + Returns: + (bool, str): + True if valid, False if not and in second part of tuple + the reason why it failed. + + """ + if not mongo: + return True, "empty string" + parsed = urlparse(mongo) + if parsed.scheme in ["mongodb", "mongodb+srv"]: + return validate_mongo_connection(mongo) + return False, "not valid mongodb schema" + + +def validate_path_string(path: str) -> (bool, str): + """Validate string if it is path to Pype repository. + + Args: + path (str): Path to validate. + Returns: (bool, str): @@ -157,22 +174,15 @@ def validate_path_string(path: str) -> (bool, str): """ if not path: - return True, "Empty string" - parsed = urlparse(path) - if parsed.scheme == "mongodb": - return validate_mongo_connection(path) - # test for uuid - try: - uuid.UUID(path) - except (ValueError, TypeError): - # not uuid - if not os.path.exists(path): - return False, "Path doesn't exist or invalid token" - return True, "Path exists" - else: - # we have pype token - # todo: implement - return False, "Not implemented yet" + return False, "empty string" + + if Path(path).exists(): + return False, "path doesn't exists" + + if not Path(path).is_dir(): + return False, "path is not directory" + + return True, "valid path" def load_environments(sections: list = None) -> dict: diff --git a/start.py b/start.py index 13514e853f..0bcbaff9e1 100644 --- a/start.py +++ b/start.py @@ -122,9 +122,6 @@ silent_commands = ["run", "igniter", "standalonepublisher"] def set_environments() -> None: """Set loaded environments. - .. deprecated:: 3.0 - no environment loading from settings until Pype version is established - .. todo: better handling of environments @@ -281,6 +278,7 @@ def _process_arguments() -> tuple: import igniter igniter.run() + return use_version, use_staging @@ -384,11 +382,19 @@ def _find_frozen_pype(use_version: str = None, return_code = run(["igniter"]) if return_code != 0: raise RuntimeError("igniter crashed.") - pype_versions = bootstrap.find_pype() + print('>>> Finding Pype again ...') + pype_versions = bootstrap.find_pype(staging=use_staging) + try: + pype_version = pype_versions[-1] + except IndexError: + print("!!! Something is wrong and we didn't found it again.") + pype_versions = None if not pype_versions: # no Pype versions found anyway, lets use then the one # shipped with frozen Pype + print("*** Still no luck finding Pype.") + print("*** We'll try to use the one coming with Pype installation.") version_path = _bootstrap_from_code(use_version) pype_version = PypeVersion( version=BootstrapRepos.get_version(version_path), @@ -452,6 +458,8 @@ def _bootstrap_from_code(use_version): pype_root = os.path.normpath( os.path.dirname(sys.executable)) local_version = bootstrap.get_version(Path(pype_root)) + print(f" - running version: {local_version}") + assert local_version else: pype_root = os.path.normpath( os.path.dirname(os.path.realpath(__file__))) @@ -604,7 +612,9 @@ def boot(): from pype.version import __version__ print(">>> loading environments ...") # Must happen before `set_modules_environments` + print(" - for Avalon ...") set_avalon_environments() + print(" - for modules ...") set_modules_environments() assert version_path, "Version path not defined."