Global: custom location for OP local versions (#4673)

* OP-5221 - updated settings for custom location of artist zip folder

* OP-5221 - updated igniter for custom location of artist zip folder

Introduced new function
Updated data_dir only after access to Mongo (DB)

* OP-5221 - pushed resolving of local folder to OpenPypeVersion

Logic in OpenPypeVersion is used even in openpype_version.py

* OP-5221 - updates after review

* OP-5221 - fix paths should be single paths

* OP-5221 - refactor to cls

* OP-5221 - refactor

Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com>

* OP-5221 - fix defaults for single paths

Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com>

* OP-5221 - remove unwanted line

Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com>

* OP-5221 - update look of Settings

Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com>
This commit is contained in:
Petr Kalis 2023-04-03 11:12:02 +02:00 committed by Jakub Trllo
parent 66c4522f9c
commit e42aebc1f2
8 changed files with 97 additions and 11 deletions

View file

@ -25,7 +25,8 @@ from .user_settings import (
from .tools import (
get_openpype_global_settings,
get_openpype_path_from_settings,
get_expected_studio_version_str
get_expected_studio_version_str,
get_local_openpype_path_from_settings
)
@ -61,6 +62,8 @@ class OpenPypeVersion(semver.VersionInfo):
"""
path = None
_local_openpype_path = None
# this should match any string complying with https://semver.org/
_VERSION_REGEX = re.compile(r"(?P<major>0|[1-9]\d*)\.(?P<minor>0|[1-9]\d*)\.(?P<patch>0|[1-9]\d*)(?:-(?P<prerelease>[a-zA-Z\d\-.]*))?(?:\+(?P<buildmetadata>[a-zA-Z\d\-.]*))?") # noqa: E501
_installed_version = None
@ -289,6 +292,23 @@ class OpenPypeVersion(semver.VersionInfo):
"""
return os.getenv("OPENPYPE_PATH")
@classmethod
def get_local_openpype_path(cls):
"""Path to unzipped versions.
By default it should be user appdata, but could be overridden by
settings.
"""
if cls._local_openpype_path:
return cls._local_openpype_path
settings = get_openpype_global_settings(os.environ["OPENPYPE_MONGO"])
data_dir = get_local_openpype_path_from_settings(settings)
if not data_dir:
data_dir = Path(user_data_dir("openpype", "pypeclub"))
cls._local_openpype_path = data_dir
return data_dir
@classmethod
def openpype_path_is_set(cls):
"""Path to OpenPype zip directory is set."""
@ -319,9 +339,8 @@ class OpenPypeVersion(semver.VersionInfo):
list: of compatible versions available on the machine.
"""
# DEPRECATED: backwards compatible way to look for versions in root
dir_to_search = Path(user_data_dir("openpype", "pypeclub"))
versions = OpenPypeVersion.get_versions_from_directory(dir_to_search)
dir_to_search = cls.get_local_openpype_path()
versions = cls.get_versions_from_directory(dir_to_search)
return list(sorted(set(versions)))
@ -533,17 +552,15 @@ class BootstrapRepos:
"""
# vendor and app used to construct user data dir
self._vendor = "pypeclub"
self._app = "openpype"
self._message = message
self._log = log.getLogger(str(__class__))
self.data_dir = Path(user_data_dir(self._app, self._vendor))
self.set_data_dir(None)
self.secure_registry = OpenPypeSecureRegistry("mongodb")
self.registry = OpenPypeSettingsRegistry()
self.zip_filter = [".pyc", "__pycache__"]
self.openpype_filter = [
"openpype", "schema", "LICENSE"
]
self._message = message
# dummy progress reporter
def empty_progress(x: int):
@ -554,6 +571,13 @@ class BootstrapRepos:
progress_callback = empty_progress
self._progress_callback = progress_callback
def set_data_dir(self, data_dir):
if not data_dir:
self.data_dir = Path(user_data_dir("openpype", "pypeclub"))
else:
self._print(f"overriding local folder: {data_dir}")
self.data_dir = data_dir
@staticmethod
def get_version_path_from_list(
version: str, version_list: list) -> Union[Path, None]:

View file

@ -14,7 +14,11 @@ from .bootstrap_repos import (
OpenPypeVersion
)
from .tools import validate_mongo_connection
from .tools import (
get_openpype_global_settings,
get_local_openpype_path_from_settings,
validate_mongo_connection
)
class InstallThread(QtCore.QThread):
@ -80,6 +84,15 @@ class InstallThread(QtCore.QThread):
return
os.environ["OPENPYPE_MONGO"] = self._mongo
if not validate_mongo_connection(self._mongo):
self.message.emit(f"Cannot connect to {self._mongo}", True)
self._set_result(-1)
return
global_settings = get_openpype_global_settings(self._mongo)
data_dir = get_local_openpype_path_from_settings(global_settings)
bs.set_data_dir(data_dir)
self.message.emit(
f"Detecting installed OpenPype versions in {bs.data_dir}",
False)

View file

@ -188,6 +188,26 @@ def get_openpype_path_from_settings(settings: dict) -> Union[str, None]:
return next((path for path in paths if os.path.exists(path)), None)
def get_local_openpype_path_from_settings(settings: dict) -> Union[str, None]:
"""Get OpenPype local path from global settings.
Used to download and unzip OP versions.
Args:
settings (dict): settings from DB.
Returns:
path to OpenPype or None if not found
"""
path = (
settings
.get("local_openpype_path", {})
.get(platform.system().lower())
)
if path:
return Path(path)
return None
def get_expected_studio_version_str(
staging=False, global_settings=None
) -> str:

View file

@ -48,6 +48,8 @@ class UpdateThread(QtCore.QThread):
"""
bs = BootstrapRepos(
progress_callback=self.set_progress, message=self.message)
bs.set_data_dir(OpenPypeVersion.get_local_openpype_path())
version_path = bs.install_version(self._openpype_version)
self._set_result(version_path)

View file

@ -15,6 +15,11 @@
"darwin": [],
"linux": []
},
"local_openpype_path": {
"windows": "",
"darwin": "",
"linux": ""
},
"production_version": "",
"staging_version": "",
"version_check_interval": 5

View file

@ -128,8 +128,12 @@
{
"type": "collapsible-wrap",
"label": "OpenPype deployment control",
"collapsible": false,
"collapsible": true,
"children": [
{
"type": "label",
"label": "Define location accessible by artist machine to check for zip updates with Openpype code."
},
{
"type": "path",
"key": "openpype_path",
@ -138,6 +142,18 @@
"multipath": true,
"require_restart": true
},
{
"type": "label",
"label": "Define custom location for artist machine where to unzip versions of Openpype code. By default it is in user app data folder."
},
{
"type": "path",
"key": "local_openpype_path",
"label": "Custom Local Versions Folder",
"multiplatform": true,
"multipath": false,
"require_restart": true
},
{
"type": "splitter"
},

View file

@ -189,6 +189,7 @@ class SettingsStateInfo:
class SettingsHandler(object):
global_keys = {
"openpype_path",
"local_openpype_path",
"admin_password",
"log_to_server",
"disk_mapping",

View file

@ -268,6 +268,7 @@ from igniter import BootstrapRepos # noqa: E402
from igniter.tools import (
get_openpype_global_settings,
get_openpype_path_from_settings,
get_local_openpype_path_from_settings,
validate_mongo_connection,
OpenPypeVersionNotFound,
OpenPypeVersionIncompatible
@ -1039,6 +1040,10 @@ def boot():
# find its versions there and bootstrap them.
openpype_path = get_openpype_path_from_settings(global_settings)
# Check if local versions should be installed in custom folder and not in
# user app data
data_dir = get_local_openpype_path_from_settings(global_settings)
bootstrap.set_data_dir(data_dir)
if getattr(sys, 'frozen', False):
local_version = bootstrap.get_version(Path(OPENPYPE_ROOT))
else:
@ -1076,7 +1081,7 @@ def boot():
_print(f"!!! {e}", True)
sys.exit(1)
# validate version
_print(f">>> Validating version [ {str(version_path)} ]")
_print(f">>> Validating version in frozen [ {str(version_path)} ]")
result = bootstrap.validate_openpype_version(version_path)
if not result[0]:
_print(f"!!! Invalid version: {result[1]}", True)