Merge pull request #442 from pypeclub/feature/standalone_publisher_as_tool
Feature/standalone publisher as tool
|
|
@ -1,14 +1,5 @@
|
|||
PUBLISH_PATHS = []
|
||||
|
||||
from .standalonepublish_module import StandAlonePublishModule
|
||||
from .app import (
|
||||
show,
|
||||
cli
|
||||
)
|
||||
__all__ = [
|
||||
"show",
|
||||
"cli"
|
||||
]
|
||||
|
||||
|
||||
def tray_init(tray_widget, main_widget):
|
||||
return StandAlonePublishModule(main_widget, tray_widget)
|
||||
|
|
|
|||
|
|
@ -1,5 +0,0 @@
|
|||
from . import cli
|
||||
|
||||
if __name__ == '__main__':
|
||||
import sys
|
||||
sys.exit(cli(sys.argv[1:]))
|
||||
|
|
@ -1,133 +0,0 @@
|
|||
import os
|
||||
import sys
|
||||
import json
|
||||
import tempfile
|
||||
import random
|
||||
import string
|
||||
|
||||
from avalon import io
|
||||
import pype
|
||||
from pype.api import execute, Logger
|
||||
|
||||
import pyblish.api
|
||||
|
||||
|
||||
log = Logger().get_logger("standalonepublisher")
|
||||
|
||||
|
||||
def set_context(project, asset, task, app):
|
||||
''' Sets context for pyblish (must be done before pyblish is launched)
|
||||
:param project: Name of `Project` where instance should be published
|
||||
:type project: str
|
||||
:param asset: Name of `Asset` where instance should be published
|
||||
:type asset: str
|
||||
'''
|
||||
os.environ["AVALON_PROJECT"] = project
|
||||
io.Session["AVALON_PROJECT"] = project
|
||||
os.environ["AVALON_ASSET"] = asset
|
||||
io.Session["AVALON_ASSET"] = asset
|
||||
if not task:
|
||||
task = ''
|
||||
os.environ["AVALON_TASK"] = task
|
||||
io.Session["AVALON_TASK"] = task
|
||||
|
||||
io.install()
|
||||
|
||||
av_project = io.find_one({'type': 'project'})
|
||||
av_asset = io.find_one({
|
||||
"type": 'asset',
|
||||
"name": asset
|
||||
})
|
||||
|
||||
parents = av_asset['data']['parents']
|
||||
hierarchy = ''
|
||||
if parents and len(parents) > 0:
|
||||
hierarchy = os.path.sep.join(parents)
|
||||
|
||||
os.environ["AVALON_HIERARCHY"] = hierarchy
|
||||
io.Session["AVALON_HIERARCHY"] = hierarchy
|
||||
|
||||
os.environ["AVALON_PROJECTCODE"] = av_project['data'].get('code', '')
|
||||
io.Session["AVALON_PROJECTCODE"] = av_project['data'].get('code', '')
|
||||
|
||||
io.Session["current_dir"] = os.path.normpath(os.getcwd())
|
||||
|
||||
os.environ["AVALON_APP"] = app
|
||||
io.Session["AVALON_APP"] = app
|
||||
|
||||
io.uninstall()
|
||||
|
||||
|
||||
def publish(data, gui=True):
|
||||
# cli pyblish seems like better solution
|
||||
return cli_publish(data, gui)
|
||||
|
||||
|
||||
def cli_publish(data, gui=True):
|
||||
from . import PUBLISH_PATHS
|
||||
|
||||
PUBLISH_SCRIPT_PATH = os.path.join(os.path.dirname(__file__), "publish.py")
|
||||
io.install()
|
||||
|
||||
# Create hash name folder in temp
|
||||
chars = "".join([random.choice(string.ascii_letters) for i in range(15)])
|
||||
staging_dir = tempfile.mkdtemp(chars)
|
||||
|
||||
# create also json and fill with data
|
||||
json_data_path = staging_dir + os.path.basename(staging_dir) + '.json'
|
||||
with open(json_data_path, 'w') as outfile:
|
||||
json.dump(data, outfile)
|
||||
|
||||
envcopy = os.environ.copy()
|
||||
envcopy["PYBLISH_HOSTS"] = "standalonepublisher"
|
||||
envcopy["SAPUBLISH_INPATH"] = json_data_path
|
||||
envcopy["PYBLISHGUI"] = "pyblish_pype"
|
||||
envcopy["PUBLISH_PATHS"] = os.pathsep.join(PUBLISH_PATHS)
|
||||
if data.get("family", "").lower() == "editorial":
|
||||
envcopy["PYBLISH_SUSPEND_LOGS"] = "1"
|
||||
|
||||
result = execute(
|
||||
[sys.executable, PUBLISH_SCRIPT_PATH],
|
||||
env=envcopy
|
||||
)
|
||||
|
||||
result = {}
|
||||
if os.path.exists(json_data_path):
|
||||
with open(json_data_path, "r") as f:
|
||||
result = json.load(f)
|
||||
|
||||
log.info(f"Publish result: {result}")
|
||||
|
||||
io.uninstall()
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def main(env):
|
||||
from avalon.tools import publish
|
||||
# Registers pype's Global pyblish plugins
|
||||
pype.install()
|
||||
|
||||
# Register additional paths
|
||||
addition_paths_str = env.get("PUBLISH_PATHS") or ""
|
||||
addition_paths = addition_paths_str.split(os.pathsep)
|
||||
for path in addition_paths:
|
||||
path = os.path.normpath(path)
|
||||
if not os.path.exists(path):
|
||||
continue
|
||||
pyblish.api.register_plugin_path(path)
|
||||
|
||||
# Register project specific plugins
|
||||
project_name = os.environ["AVALON_PROJECT"]
|
||||
project_plugins_paths = env.get("PYPE_PROJECT_PLUGINS") or ""
|
||||
for path in project_plugins_paths.split(os.pathsep):
|
||||
plugin_path = os.path.join(path, project_name, "plugins")
|
||||
if os.path.exists(plugin_path):
|
||||
pyblish.api.register_plugin_path(plugin_path)
|
||||
|
||||
return publish.show()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
result = main(os.environ)
|
||||
sys.exit(not bool(result))
|
||||
|
|
@ -1,21 +1,22 @@
|
|||
import os
|
||||
from .app import show
|
||||
from .widgets import QtWidgets
|
||||
import sys
|
||||
import subprocess
|
||||
import pype
|
||||
from . import PUBLISH_PATHS
|
||||
from pype import tools
|
||||
|
||||
|
||||
class StandAlonePublishModule:
|
||||
|
||||
def __init__(self, main_parent=None, parent=None):
|
||||
self.main_parent = main_parent
|
||||
self.parent_widget = parent
|
||||
PUBLISH_PATHS.clear()
|
||||
PUBLISH_PATHS.append(os.path.sep.join(
|
||||
[pype.PLUGINS_DIR, "standalonepublisher", "publish"]
|
||||
))
|
||||
self.publish_paths = [
|
||||
os.path.join(
|
||||
pype.PLUGINS_DIR, "standalonepublisher", "publish"
|
||||
)
|
||||
]
|
||||
|
||||
def tray_menu(self, parent_menu):
|
||||
from Qt import QtWidgets
|
||||
self.run_action = QtWidgets.QAction(
|
||||
"Publish", parent_menu
|
||||
)
|
||||
|
|
@ -24,9 +25,17 @@ class StandAlonePublishModule:
|
|||
|
||||
def process_modules(self, modules):
|
||||
if "FtrackModule" in modules:
|
||||
PUBLISH_PATHS.append(os.path.sep.join(
|
||||
[pype.PLUGINS_DIR, "ftrack", "publish"]
|
||||
self.publish_paths.append(os.path.join(
|
||||
pype.PLUGINS_DIR, "ftrack", "publish"
|
||||
))
|
||||
|
||||
def show(self):
|
||||
show(self.main_parent, False)
|
||||
standalone_publisher_tool_path = os.path.join(
|
||||
os.path.dirname(tools.__file__),
|
||||
"standalonepublish"
|
||||
)
|
||||
subprocess.Popen([
|
||||
sys.executable,
|
||||
standalone_publisher_tool_path,
|
||||
os.pathsep.join(self.publish_paths).replace("\\", "/")
|
||||
])
|
||||
|
|
|
|||
|
|
@ -1,113 +0,0 @@
|
|||
from xml.dom import minidom
|
||||
|
||||
from . import QtGui, QtCore, QtWidgets
|
||||
from PyQt5 import QtSvg, QtXml
|
||||
|
||||
|
||||
class SvgResizable(QtSvg.QSvgWidget):
|
||||
clicked = QtCore.Signal()
|
||||
|
||||
def __init__(self, filepath, width=None, height=None, fill=None):
|
||||
super().__init__()
|
||||
self.xmldoc = minidom.parse(filepath)
|
||||
itemlist = self.xmldoc.getElementsByTagName('svg')
|
||||
for element in itemlist:
|
||||
if fill:
|
||||
element.setAttribute('fill', str(fill))
|
||||
# TODO auto scale if only one is set
|
||||
if width is not None and height is not None:
|
||||
self.setMaximumSize(width, height)
|
||||
self.setMinimumSize(width, height)
|
||||
xml_string = self.xmldoc.toxml()
|
||||
svg_bytes = bytearray(xml_string, encoding='utf-8')
|
||||
|
||||
self.load(svg_bytes)
|
||||
|
||||
def change_color(self, color):
|
||||
element = self.xmldoc.getElementsByTagName('svg')[0]
|
||||
element.setAttribute('fill', str(color))
|
||||
xml_string = self.xmldoc.toxml()
|
||||
svg_bytes = bytearray(xml_string, encoding='utf-8')
|
||||
self.load(svg_bytes)
|
||||
|
||||
def mousePressEvent(self, event):
|
||||
self.clicked.emit()
|
||||
|
||||
|
||||
class SvgButton(QtWidgets.QFrame):
|
||||
clicked = QtCore.Signal()
|
||||
def __init__(
|
||||
self, filepath, width=None, height=None, fills=[],
|
||||
parent=None, checkable=True
|
||||
):
|
||||
super().__init__(parent)
|
||||
self.checkable = checkable
|
||||
self.checked = False
|
||||
|
||||
xmldoc = minidom.parse(filepath)
|
||||
element = xmldoc.getElementsByTagName('svg')[0]
|
||||
c_actual = '#777777'
|
||||
if element.hasAttribute('fill'):
|
||||
c_actual = element.getAttribute('fill')
|
||||
self.store_fills(fills, c_actual)
|
||||
|
||||
self.installEventFilter(self)
|
||||
self.svg_widget = SvgResizable(filepath, width, height, self.c_normal)
|
||||
xmldoc = minidom.parse(filepath)
|
||||
|
||||
layout = QtWidgets.QHBoxLayout(self)
|
||||
layout.setSpacing(0)
|
||||
layout.setContentsMargins(0, 0, 0, 0)
|
||||
layout.addWidget(self.svg_widget)
|
||||
|
||||
if width is not None and height is not None:
|
||||
self.setMaximumSize(width, height)
|
||||
self.setMinimumSize(width, height)
|
||||
|
||||
def store_fills(self, fills, actual):
|
||||
if len(fills) == 0:
|
||||
fills = [actual, actual, actual, actual]
|
||||
elif len(fills) == 1:
|
||||
fills = [fills[0], fills[0], fills[0], fills[0]]
|
||||
elif len(fills) == 2:
|
||||
fills = [fills[0], fills[1], fills[1], fills[1]]
|
||||
elif len(fills) == 3:
|
||||
fills = [fills[0], fills[1], fills[2], fills[2]]
|
||||
self.c_normal = fills[0]
|
||||
self.c_hover = fills[1]
|
||||
self.c_active = fills[2]
|
||||
self.c_active_hover = fills[3]
|
||||
|
||||
def eventFilter(self, object, event):
|
||||
if event.type() == QtCore.QEvent.Enter:
|
||||
self.hoverEnterEvent(event)
|
||||
return True
|
||||
elif event.type() == QtCore.QEvent.Leave:
|
||||
self.hoverLeaveEvent(event)
|
||||
return True
|
||||
elif event.type() == QtCore.QEvent.MouseButtonRelease:
|
||||
self.mousePressEvent(event)
|
||||
return False
|
||||
|
||||
def change_checked(self, hover=True):
|
||||
if self.checkable:
|
||||
self.checked = not self.checked
|
||||
if hover:
|
||||
self.hoverEnterEvent()
|
||||
else:
|
||||
self.hoverLeaveEvent()
|
||||
|
||||
def hoverEnterEvent(self, event=None):
|
||||
color = self.c_hover
|
||||
if self.checked:
|
||||
color = self.c_active_hover
|
||||
self.svg_widget.change_color(color)
|
||||
|
||||
def hoverLeaveEvent(self, event=None):
|
||||
color = self.c_normal
|
||||
if self.checked:
|
||||
color = self.c_active
|
||||
self.svg_widget.change_color(color)
|
||||
|
||||
def mousePressEvent(self, event=None):
|
||||
self.clicked.emit()
|
||||
8
pype/tools/standalonepublish/__init__.py
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
from .app import (
|
||||
show,
|
||||
cli
|
||||
)
|
||||
__all__ = [
|
||||
"show",
|
||||
"cli"
|
||||
]
|
||||
24
pype/tools/standalonepublish/__main__.py
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
import os
|
||||
import sys
|
||||
import app
|
||||
import signal
|
||||
from Qt import QtWidgets
|
||||
from avalon import style
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
qt_app = QtWidgets.QApplication([])
|
||||
# app.setQuitOnLastWindowClosed(False)
|
||||
qt_app.setStyleSheet(style.load_stylesheet())
|
||||
|
||||
def signal_handler(sig, frame):
|
||||
print("You pressed Ctrl+C. Process ended.")
|
||||
qt_app.quit()
|
||||
|
||||
signal.signal(signal.SIGINT, signal_handler)
|
||||
signal.signal(signal.SIGTERM, signal_handler)
|
||||
|
||||
window = app.Window(sys.argv[-1].split(os.pathsep))
|
||||
window.show()
|
||||
|
||||
sys.exit(qt_app.exec_())
|
||||
|
|
@ -1,18 +1,8 @@
|
|||
import os
|
||||
import sys
|
||||
import json
|
||||
from subprocess import Popen
|
||||
from bson.objectid import ObjectId
|
||||
from pype import lib as pypelib
|
||||
from avalon.vendor.Qt import QtWidgets, QtCore
|
||||
from avalon import api, style, schema
|
||||
from avalon.tools import lib as parentlib
|
||||
from .widgets import *
|
||||
# Move this to pype lib?
|
||||
from Qt import QtWidgets, QtCore
|
||||
from widgets import AssetWidget, FamilyWidget, ComponentsWidget, ShadowWidget
|
||||
from avalon.tools.libraryloader.io_nonsingleton import DbConnector
|
||||
|
||||
module = sys.modules[__name__]
|
||||
module.window = None
|
||||
|
||||
class Window(QtWidgets.QDialog):
|
||||
"""Main window of Standalone publisher.
|
||||
|
|
@ -28,14 +18,15 @@ class Window(QtWidgets.QDialog):
|
|||
WIDTH = 1100
|
||||
HEIGHT = 500
|
||||
|
||||
def __init__(self, parent=None):
|
||||
def __init__(self, pyblish_paths, parent=None):
|
||||
super(Window, self).__init__(parent=parent)
|
||||
self._db.install()
|
||||
|
||||
self.pyblish_paths = pyblish_paths
|
||||
|
||||
self.setWindowTitle("Standalone Publish")
|
||||
self.setFocusPolicy(QtCore.Qt.StrongFocus)
|
||||
self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
|
||||
self.setStyleSheet(style.load_stylesheet())
|
||||
|
||||
# Validators
|
||||
self.valid_parent = False
|
||||
|
|
@ -99,8 +90,14 @@ class Window(QtWidgets.QDialog):
|
|||
def resizeEvent(self, event=None):
|
||||
''' Helps resize shadow widget
|
||||
'''
|
||||
position_x = (self.frameGeometry().width()-self.shadow_widget.frameGeometry().width())/2
|
||||
position_y = (self.frameGeometry().height()-self.shadow_widget.frameGeometry().height())/2
|
||||
position_x = (
|
||||
self.frameGeometry().width()
|
||||
- self.shadow_widget.frameGeometry().width()
|
||||
) / 2
|
||||
position_y = (
|
||||
self.frameGeometry().height()
|
||||
- self.shadow_widget.frameGeometry().height()
|
||||
) / 2
|
||||
self.shadow_widget.move(position_x, position_y)
|
||||
w = self.frameGeometry().width()
|
||||
h = self.frameGeometry().height()
|
||||
|
|
@ -144,7 +141,10 @@ class Window(QtWidgets.QDialog):
|
|||
- files/folders in clipboard (tested only on Windows OS)
|
||||
- copied path of file/folder in clipboard ('c:/path/to/folder')
|
||||
'''
|
||||
if event.key() == QtCore.Qt.Key_V and event.modifiers() == QtCore.Qt.ControlModifier:
|
||||
if (
|
||||
event.key() == QtCore.Qt.Key_V
|
||||
and event.modifiers() == QtCore.Qt.ControlModifier
|
||||
):
|
||||
clip = QtWidgets.QApplication.clipboard()
|
||||
self.widget_components.process_mime_data(clip)
|
||||
super().keyPressEvent(event)
|
||||
|
|
@ -190,29 +190,3 @@ class Window(QtWidgets.QDialog):
|
|||
data.update(self.widget_components.collect_data())
|
||||
|
||||
return data
|
||||
|
||||
def show(parent=None, debug=False):
|
||||
try:
|
||||
module.window.close()
|
||||
del module.window
|
||||
except (RuntimeError, AttributeError):
|
||||
pass
|
||||
|
||||
with parentlib.application():
|
||||
window = Window(parent)
|
||||
window.show()
|
||||
|
||||
module.window = window
|
||||
|
||||
|
||||
def cli(args):
|
||||
import argparse
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("project")
|
||||
parser.add_argument("asset")
|
||||
|
||||
args = parser.parse_args(args)
|
||||
# project = args.project
|
||||
# asset = args.asset
|
||||
|
||||
show()
|
||||
35
pype/tools/standalonepublish/publish.py
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
import os
|
||||
import sys
|
||||
|
||||
import pype
|
||||
import pyblish.api
|
||||
|
||||
|
||||
def main(env):
|
||||
from avalon.tools import publish
|
||||
# Registers pype's Global pyblish plugins
|
||||
pype.install()
|
||||
|
||||
# Register additional paths
|
||||
addition_paths_str = env.get("PUBLISH_PATHS") or ""
|
||||
addition_paths = addition_paths_str.split(os.pathsep)
|
||||
for path in addition_paths:
|
||||
path = os.path.normpath(path)
|
||||
if not os.path.exists(path):
|
||||
continue
|
||||
pyblish.api.register_plugin_path(path)
|
||||
|
||||
# Register project specific plugins
|
||||
project_name = os.environ["AVALON_PROJECT"]
|
||||
project_plugins_paths = env.get("PYPE_PROJECT_PLUGINS") or ""
|
||||
for path in project_plugins_paths.split(os.pathsep):
|
||||
plugin_path = os.path.join(path, project_name, "plugins")
|
||||
if os.path.exists(plugin_path):
|
||||
pyblish.api.register_plugin_path(plugin_path)
|
||||
|
||||
return publish.show()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
result = main(os.environ)
|
||||
sys.exit(not bool(result))
|
||||
|
Before Width: | Height: | Size: 730 B After Width: | Height: | Size: 730 B |
|
Before Width: | Height: | Size: 803 B After Width: | Height: | Size: 803 B |
|
Before Width: | Height: | Size: 484 B After Width: | Height: | Size: 484 B |
|
Before Width: | Height: | Size: 257 KiB After Width: | Height: | Size: 257 KiB |
|
Before Width: | Height: | Size: 5 KiB After Width: | Height: | Size: 5 KiB |
|
Before Width: | Height: | Size: 8.4 KiB After Width: | Height: | Size: 8.4 KiB |
|
Before Width: | Height: | Size: 1 KiB After Width: | Height: | Size: 1 KiB |
|
Before Width: | Height: | Size: 41 KiB After Width: | Height: | Size: 41 KiB |
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 48 KiB |
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 120 B After Width: | Height: | Size: 120 B |
|
|
@ -1,6 +1,4 @@
|
|||
from avalon.vendor.Qt import *
|
||||
from avalon.vendor import qtawesome
|
||||
from avalon import style
|
||||
from Qt import QtCore
|
||||
|
||||
HelpRole = QtCore.Qt.UserRole + 2
|
||||
FamilyRole = QtCore.Qt.UserRole + 3
|
||||
|
|
@ -8,9 +6,6 @@ ExistsRole = QtCore.Qt.UserRole + 4
|
|||
PluginRole = QtCore.Qt.UserRole + 5
|
||||
PluginKeyRole = QtCore.Qt.UserRole + 6
|
||||
|
||||
from ..resources import get_resource
|
||||
from .button_from_svgs import SvgResizable, SvgButton
|
||||
|
||||
from .model_node import Node
|
||||
from .model_tree import TreeModel
|
||||
from .model_asset import AssetModel, _iter_model_rows
|
||||
|
|
@ -1,8 +1,9 @@
|
|||
import logging
|
||||
import collections
|
||||
from . import QtCore, QtGui
|
||||
from Qt import QtCore, QtGui
|
||||
from . import TreeModel, Node
|
||||
from . import style, qtawesome
|
||||
from avalon.vendor import qtawesome
|
||||
from avalon import style
|
||||
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
from . import QtCore
|
||||
from Qt import QtCore
|
||||
|
||||
|
||||
class ExactMatchesFilterProxyModel(QtCore.QSortFilterProxyModel):
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
from . import QtCore
|
||||
from Qt import QtCore
|
||||
import re
|
||||
|
||||
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
from . import QtCore, TreeModel
|
||||
from . import Node
|
||||
from . import qtawesome, style
|
||||
from Qt import QtCore
|
||||
from . import Node, TreeModel
|
||||
from avalon.vendor import qtawesome
|
||||
from avalon import style
|
||||
|
||||
|
||||
class TasksTemplateModel(TreeModel):
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
from . import QtCore
|
||||
from Qt import QtCore
|
||||
from . import Node
|
||||
|
||||
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
from . import QtWidgets, QtCore
|
||||
from Qt import QtWidgets, QtCore
|
||||
|
||||
|
||||
class DeselectableTreeView(QtWidgets.QTreeView):
|
||||
|
|
@ -1,7 +1,8 @@
|
|||
import contextlib
|
||||
from . import QtWidgets, QtCore
|
||||
from Qt import QtWidgets, QtCore
|
||||
from . import RecursiveSortFilterProxyModel, AssetModel
|
||||
from . import qtawesome, style
|
||||
from avalon.vendor import qtawesome
|
||||
from avalon import style
|
||||
from . import TasksTemplateModel, DeselectableTreeView
|
||||
from . import _iter_model_rows
|
||||
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
import os
|
||||
from . import QtCore, QtGui, QtWidgets
|
||||
from . import get_resource
|
||||
from Qt import QtCore, QtGui, QtWidgets
|
||||
from pype.resources import get_resource
|
||||
from avalon import style
|
||||
|
||||
|
||||
|
|
@ -1,7 +1,16 @@
|
|||
from . import QtWidgets, QtCore, QtGui
|
||||
from . import DropDataFrame
|
||||
import os
|
||||
import sys
|
||||
import json
|
||||
import tempfile
|
||||
import random
|
||||
import string
|
||||
|
||||
from .. import publish
|
||||
from Qt import QtWidgets, QtCore
|
||||
from . import DropDataFrame
|
||||
from avalon import io
|
||||
from pype.api import execute, Logger
|
||||
|
||||
log = Logger().get_logger("standalonepublisher")
|
||||
|
||||
|
||||
class ComponentsWidget(QtWidgets.QWidget):
|
||||
|
|
@ -113,16 +122,103 @@ class ComponentsWidget(QtWidgets.QWidget):
|
|||
self.parent_widget.working_stop()
|
||||
|
||||
def _publish(self):
|
||||
log.info(self.parent_widget.pyblish_paths)
|
||||
self.working_start('Pyblish is running')
|
||||
try:
|
||||
data = self.parent_widget.collect_data()
|
||||
publish.set_context(
|
||||
data['project'], data['asset'], data['task'], 'standalonepublish'
|
||||
set_context(
|
||||
data['project'],
|
||||
data['asset'],
|
||||
data['task']
|
||||
)
|
||||
result = publish.publish(data)
|
||||
result = cli_publish(data, self.parent_widget.pyblish_paths)
|
||||
# Clear widgets from components list if publishing was successful
|
||||
if result:
|
||||
self.drop_frame.components_list.clear_widgets()
|
||||
self.drop_frame._refresh_view()
|
||||
finally:
|
||||
self.working_stop()
|
||||
|
||||
|
||||
def set_context(project, asset, task):
|
||||
''' Sets context for pyblish (must be done before pyblish is launched)
|
||||
:param project: Name of `Project` where instance should be published
|
||||
:type project: str
|
||||
:param asset: Name of `Asset` where instance should be published
|
||||
:type asset: str
|
||||
'''
|
||||
os.environ["AVALON_PROJECT"] = project
|
||||
io.Session["AVALON_PROJECT"] = project
|
||||
os.environ["AVALON_ASSET"] = asset
|
||||
io.Session["AVALON_ASSET"] = asset
|
||||
if not task:
|
||||
task = ''
|
||||
os.environ["AVALON_TASK"] = task
|
||||
io.Session["AVALON_TASK"] = task
|
||||
|
||||
io.install()
|
||||
|
||||
av_project = io.find_one({'type': 'project'})
|
||||
av_asset = io.find_one({
|
||||
"type": 'asset',
|
||||
"name": asset
|
||||
})
|
||||
|
||||
parents = av_asset['data']['parents']
|
||||
hierarchy = ''
|
||||
if parents and len(parents) > 0:
|
||||
hierarchy = os.path.sep.join(parents)
|
||||
|
||||
os.environ["AVALON_HIERARCHY"] = hierarchy
|
||||
io.Session["AVALON_HIERARCHY"] = hierarchy
|
||||
|
||||
os.environ["AVALON_PROJECTCODE"] = av_project['data'].get('code', '')
|
||||
io.Session["AVALON_PROJECTCODE"] = av_project['data'].get('code', '')
|
||||
|
||||
io.Session["current_dir"] = os.path.normpath(os.getcwd())
|
||||
|
||||
os.environ["AVALON_APP"] = "standalonepublish"
|
||||
io.Session["AVALON_APP"] = "standalonepublish"
|
||||
|
||||
io.uninstall()
|
||||
|
||||
|
||||
def cli_publish(data, publish_paths, gui=True):
|
||||
PUBLISH_SCRIPT_PATH = os.path.join(
|
||||
os.path.dirname(os.path.dirname(__file__)),
|
||||
"publish.py"
|
||||
)
|
||||
io.install()
|
||||
|
||||
# Create hash name folder in temp
|
||||
chars = "".join([random.choice(string.ascii_letters) for i in range(15)])
|
||||
staging_dir = tempfile.mkdtemp(chars)
|
||||
|
||||
# create also json and fill with data
|
||||
json_data_path = staging_dir + os.path.basename(staging_dir) + '.json'
|
||||
with open(json_data_path, 'w') as outfile:
|
||||
json.dump(data, outfile)
|
||||
|
||||
envcopy = os.environ.copy()
|
||||
envcopy["PYBLISH_HOSTS"] = "standalonepublisher"
|
||||
envcopy["SAPUBLISH_INPATH"] = json_data_path
|
||||
envcopy["PYBLISHGUI"] = "pyblish_pype"
|
||||
envcopy["PUBLISH_PATHS"] = os.pathsep.join(publish_paths)
|
||||
if data.get("family", "").lower() == "editorial":
|
||||
envcopy["PYBLISH_SUSPEND_LOGS"] = "1"
|
||||
|
||||
result = execute(
|
||||
[sys.executable, PUBLISH_SCRIPT_PATH],
|
||||
env=envcopy
|
||||
)
|
||||
|
||||
result = {}
|
||||
if os.path.exists(json_data_path):
|
||||
with open(json_data_path, "r") as f:
|
||||
result = json.load(f)
|
||||
|
||||
log.info(f"Publish result: {result}")
|
||||
|
||||
io.uninstall()
|
||||
|
||||
return False
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
from . import QtCore, QtGui, QtWidgets
|
||||
from Qt import QtWidgets
|
||||
|
||||
|
||||
class ComponentsList(QtWidgets.QTableWidget):
|
||||
|
|
@ -1,7 +1,4 @@
|
|||
import os
|
||||
import logging
|
||||
import clique
|
||||
from . import QtWidgets, QtCore, QtGui
|
||||
from Qt import QtWidgets, QtCore, QtGui
|
||||
|
||||
|
||||
class DropEmpty(QtWidgets.QWidget):
|
||||
|
|
@ -42,11 +39,13 @@ class DropEmpty(QtWidgets.QWidget):
|
|||
super().paintEvent(event)
|
||||
painter = QtGui.QPainter(self)
|
||||
pen = QtGui.QPen()
|
||||
pen.setWidth(1);
|
||||
pen.setBrush(QtCore.Qt.darkGray);
|
||||
pen.setStyle(QtCore.Qt.DashLine);
|
||||
pen.setWidth(1)
|
||||
pen.setBrush(QtCore.Qt.darkGray)
|
||||
pen.setStyle(QtCore.Qt.DashLine)
|
||||
painter.setPen(pen)
|
||||
painter.drawRect(
|
||||
10, 10,
|
||||
self.rect().width()-15, self.rect().height()-15
|
||||
10,
|
||||
10,
|
||||
self.rect().width() - 15,
|
||||
self.rect().height() - 15
|
||||
)
|
||||
|
|
@ -3,9 +3,8 @@ import re
|
|||
import json
|
||||
import clique
|
||||
import subprocess
|
||||
from pype.api import config
|
||||
import pype.lib
|
||||
from . import QtWidgets, QtCore
|
||||
from Qt import QtWidgets, QtCore
|
||||
from . import DropEmpty, ComponentsList, ComponentItem
|
||||
|
||||
|
||||
|
|
@ -1,10 +1,6 @@
|
|||
import os
|
||||
import sys
|
||||
import inspect
|
||||
import json
|
||||
from collections import namedtuple
|
||||
|
||||
from . import QtWidgets, QtCore
|
||||
from Qt import QtWidgets, QtCore
|
||||
from . import HelpRole, FamilyRole, ExistsRole, PluginRole, PluginKeyRole
|
||||
from . import FamilyDescriptionWidget
|
||||
|
||||
|
|
@ -1,13 +1,7 @@
|
|||
import os
|
||||
import sys
|
||||
import inspect
|
||||
import json
|
||||
|
||||
from . import QtWidgets, QtCore, QtGui
|
||||
from . import HelpRole, FamilyRole, ExistsRole, PluginRole
|
||||
from . import qtawesome
|
||||
from Qt import QtWidgets, QtCore, QtGui
|
||||
from . import FamilyRole, PluginRole
|
||||
from avalon.vendor import qtawesome
|
||||
import six
|
||||
from pype import lib as pypelib
|
||||
|
||||
|
||||
class FamilyDescriptionWidget(QtWidgets.QWidget):
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
from . import QtWidgets, QtCore, QtGui
|
||||
from Qt import QtWidgets, QtCore, QtGui
|
||||
|
||||
|
||||
class ShadowWidget(QtWidgets.QWidget):
|
||||
|
|
@ -26,7 +26,9 @@ class ShadowWidget(QtWidgets.QWidget):
|
|||
painter.begin(self)
|
||||
painter.setFont(self.font)
|
||||
painter.setRenderHint(QtGui.QPainter.Antialiasing)
|
||||
painter.fillRect(event.rect(), QtGui.QBrush(QtGui.QColor(0, 0, 0, 127)))
|
||||
painter.fillRect(
|
||||
event.rect(), QtGui.QBrush(QtGui.QColor(0, 0, 0, 127))
|
||||
)
|
||||
painter.drawText(
|
||||
QtCore.QRectF(
|
||||
0.0,
|
||||
|
|
@ -34,7 +36,7 @@ class ShadowWidget(QtWidgets.QWidget):
|
|||
self.parent_widget.frameGeometry().width(),
|
||||
self.parent_widget.frameGeometry().height()
|
||||
),
|
||||
QtCore.Qt.AlignCenter|QtCore.Qt.AlignCenter,
|
||||
QtCore.Qt.AlignCenter | QtCore.Qt.AlignCenter,
|
||||
self.message
|
||||
)
|
||||
painter.end()
|
||||