blender_asset_tracer/pack/shaman/__init__.py

146 lines
4.8 KiB
Python
Raw Normal View History

2021-10-18 15:54:04 +02:00
# ***** BEGIN GPL LICENSE BLOCK *****
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
# ***** END GPL LICENCE BLOCK *****
#
# (c) 2019, Blender Foundation - Sybren A. Stüvel
2023-01-10 11:41:55 +01:00
"""Shaman Client interface.
Note that this supports the Shaman API of Flamenco Manager 2.x. Support for
Flamenco 3.x will be implemented in a new Flamenco Blender add-on, and not in
BAT itself.
"""
2021-10-18 15:54:04 +02:00
import logging
import os
import pathlib
import typing
import urllib.parse
import requests
import blender_asset_tracer.pack as bat_pack
import blender_asset_tracer.pack.transfer as bat_transfer
from .transfer import ShamanTransferrer
from .client import ShamanClient
log = logging.getLogger(__name__)
class ShamanPacker(bat_pack.Packer):
"""Creates BAT Packs on a Shaman server."""
2023-01-10 11:41:55 +01:00
def __init__(
self,
bfile: pathlib.Path,
project: pathlib.Path,
target: str,
endpoint: str,
checkout_id: str,
**kwargs
) -> None:
2021-10-18 15:54:04 +02:00
"""Constructor
:param target: mock target '/' to construct project-relative paths.
:param endpoint: URL of the Shaman endpoint.
"""
super().__init__(bfile, project, target, **kwargs)
self.checkout_id = checkout_id
self.shaman_endpoint = endpoint
2023-01-10 11:41:55 +01:00
self._checkout_location = ""
2021-10-18 15:54:04 +02:00
def _get_auth_token(self) -> str:
# TODO: get a token from the Flamenco Server.
2023-01-10 11:41:55 +01:00
token_from_env = os.environ.get("SHAMAN_JWT_TOKEN")
2021-10-18 15:54:04 +02:00
if token_from_env:
return token_from_env
2023-01-10 11:41:55 +01:00
log.warning(
"Using temporary hack to get auth token from Shaman, "
"set SHAMAN_JTW_TOKEN to prevent"
)
unauth_shaman = ShamanClient("", self.shaman_endpoint)
resp = unauth_shaman.get("get-token", timeout=10)
2021-10-18 15:54:04 +02:00
resp.raise_for_status()
return resp.text
def _create_file_transferer(self) -> bat_transfer.FileTransferer:
# TODO: pass self._get_auth_token itself, so that the Transferer will be able to
# decide when to get this token (and how many times).
auth_token = self._get_auth_token()
2023-01-10 11:41:55 +01:00
return ShamanTransferrer(
auth_token, self.project, self.shaman_endpoint, self.checkout_id
)
2021-10-18 15:54:04 +02:00
def _make_target_path(self, target: str) -> pathlib.PurePath:
2023-01-10 11:41:55 +01:00
return pathlib.PurePosixPath("/")
2021-10-18 15:54:04 +02:00
def _on_file_transfer_finished(self, *, file_transfer_completed: bool):
2023-01-10 11:41:55 +01:00
super()._on_file_transfer_finished(
file_transfer_completed=file_transfer_completed
)
2021-10-18 15:54:04 +02:00
assert isinstance(self._file_transferer, ShamanTransferrer)
self._checkout_location = self._file_transferer.checkout_location
@property
def checkout_location(self) -> str:
"""Return the checkout location of the packed blend file.
:return: the checkout location, or '' if no checkout was made.
"""
return self._checkout_location
@property
def output_path(self) -> pathlib.PurePath:
"""The path of the packed blend file in the target directory."""
assert self._output_path is not None
checkout_location = pathlib.PurePosixPath(self._checkout_location)
rel_output = self._output_path.relative_to(self._target_path)
return checkout_location / rel_output
def execute(self):
try:
super().execute()
except requests.exceptions.ConnectionError as ex:
2023-01-10 11:41:55 +01:00
log.exception("Error communicating with Shaman")
2021-10-18 15:54:04 +02:00
self.abort(str(ex))
self._check_aborted()
def parse_endpoint(shaman_url: str) -> typing.Tuple[str, str]:
"""Convert shaman://hostname/path#checkoutID into endpoint URL + checkout ID."""
urlparts = urllib.parse.urlparse(str(shaman_url))
2023-01-10 11:41:55 +01:00
if urlparts.scheme in {"shaman", "shaman+https"}:
scheme = "https"
elif urlparts.scheme == "shaman+http":
scheme = "http"
2021-10-18 15:54:04 +02:00
else:
2023-01-10 11:41:55 +01:00
raise ValueError(
"Invalid scheme %r, choose shaman:// or shaman+http://", urlparts.scheme
)
2021-10-18 15:54:04 +02:00
checkout_id = urllib.parse.unquote(urlparts.fragment)
2023-01-10 11:41:55 +01:00
path = urlparts.path or "/"
new_urlparts = (scheme, urlparts.netloc, path, *urlparts[3:-1], "")
2021-10-18 15:54:04 +02:00
endpoint = urllib.parse.urlunparse(new_urlparts)
return endpoint, checkout_id