Added feature for set MongoId to Ftrack

This commit is contained in:
Jakub Trllo 2018-10-18 11:53:49 +02:00
parent 2ae76c2d5b
commit f56fdc0700
4 changed files with 383 additions and 38 deletions

View file

@ -0,0 +1,127 @@
# :coding: utf-8
# :copyright: Copyright (c) 2017 ftrack
import sys
import argparse
import logging
import collections
import os
import datetime
import json
import ftrack_api
from ftrack_action_handler.action import BaseAction
from avalon import io, inventory, schema
from avalon.vendor import toml
class JobKiller(BaseAction):
'''Edit meta data action.'''
#: Action identifier.
identifier = 'job.kill'
#: Action label.
label = 'Job Killer'
#: Action description.
description = 'Killing all running jobs younger than day'
def validate_selection(self, session, entities):
'''Return if *entities* is a valid selection.'''
# if (len(entities) != 1):
# # If entities contains more than one item return early since
# # metadata cannot be edited for several entites at the same time.
# return False
pass
# entity_type, entity_id = entities[0]
# if (
# entity_type not in session.types
# ):
# # Return False if the target entity does not have a metadata
# # attribute.
# return False
return True
def discover(self, session, entities, event):
'''Return True if action is valid.'''
self.logger.info('Got selection: {0}'.format(entities))
return self.validate_selection(session, entities)
def launch(self, session, entities, event):
""" JOB SETTING """
yesterday = datetime.date.today() - datetime.timedelta(days=1)
jobs = session.query(
'select id, status from Job '
'where status in ("queued", "running") and created_at > {0}'.format(yesterday)
)
# Update all the queried jobs, setting the status to failed.
for job in jobs:
print(job['created_at'])
print('Changing Job ({}) status: {} -> failed'.format(job['id'], job['status']))
job['status'] = 'failed'
session.commit()
print('Complete')
return True
def register(session, **kw):
'''Register plugin. Called when used as an plugin.'''
# Validate that session is an instance of ftrack_api.Session. If not,
# assume that register is being called from an old or incompatible API and
# return without doing anything.
if not isinstance(session, ftrack_api.session.Session):
return
action_handler = JobKiller(session)
action_handler.register()
def main(arguments=None):
'''Set up logging and register action.'''
if arguments is None:
arguments = []
parser = argparse.ArgumentParser()
# Allow setting of logging level from arguments.
loggingLevels = {}
for level in (
logging.NOTSET, logging.DEBUG, logging.INFO, logging.WARNING,
logging.ERROR, logging.CRITICAL
):
loggingLevels[logging.getLevelName(level).lower()] = level
parser.add_argument(
'-v', '--verbosity',
help='Set the logging output verbosity.',
choices=loggingLevels.keys(),
default='info'
)
namespace = parser.parse_args(arguments)
# Set up basic logging
logging.basicConfig(level=loggingLevels[namespace.verbosity])
session = ftrack_api.Session(
server_url="https://pype.ftrackapp.com",
api_key="4e01eda0-24b3-4451-8e01-70edc03286be",
api_user="jakub.trllo"
)
register(session)
# Wait for events
logging.info(
'Registered actions and listening for events. Use Ctrl-C to abort.'
)
session.event_hub.wait()
if __name__ == '__main__':
raise SystemExit(main(sys.argv[1:]))

View file

@ -51,8 +51,9 @@ class SyncToAvalon(BaseAction):
def importToAvalon(self, session, entity):
eLinks = []
custAttrName = 'avalon_mongo_id'
# TODO read from file, which data are in scope???
""" get needed info of entity and all parents """
# get needed info of entity and all parents
for e in entity['link']:
tmp = session.get(e['type'], e['id'])
if e['name'].find(" ") == -1:
@ -65,7 +66,7 @@ class SyncToAvalon(BaseAction):
entityProj = session.get(eLinks[0]['type'], eLinks[0]['ftrackId'])
""" set AVALON_PROJECT env """
# set AVALON_PROJECT env
os.environ["AVALON_PROJECT"] = entityProj["full_name"]
# get schema of project TODO read different schemas based on project type
@ -89,8 +90,10 @@ class SyncToAvalon(BaseAction):
# Store project Id
projectId = io.find_one({"type": "project", "name": entityProj["full_name"]})["_id"]
if custAttrName in entityProj['custom_attributes'] and entityProj['custom_attributes'][custAttrName] is '':
entityProj['custom_attributes'][custAttrName] = str(projectId)
# If entity is Project or is Silo kill action
# If entity is Project or Silo kill action
if (len(eLinks) > 2) and not (eLinks[-1]['type'] in ['Project']):
silo = eLinks[1]
@ -102,13 +105,12 @@ class SyncToAvalon(BaseAction):
folderStruct = []
folderStruct.append(silo['name'])
parentId = None
data = {'ftrackId': None, 'visualParent': parentId, 'parents': folderStruct,
'entityType': None}
data = {'visualParent': parentId, 'parents': folderStruct,
'ftrackId': None, 'entityType': None}
for asset in assets:
data = {'ftrackId': asset['ftrackId'], 'visualParent': data['visualParent'],
'parents': data['parents'], 'entityType': asset['type']}
if (io.find_one({'type': 'asset', 'name': asset['name']}) == None):
data.update({'ftrackId': asset['ftrackId'], 'entityType': asset['type']})
if (io.find_one({'type': 'asset', 'name': asset['name']}) is None):
inventory.create_asset(asset['name'], silo['name'], data, projectId)
print("Asset "+asset['name']+" created")
@ -118,13 +120,18 @@ class SyncToAvalon(BaseAction):
print("Asset "+asset["name"]+" already exist")
parentId = io.find_one({'type': 'asset', 'name': asset['name']})['_id']
data = {'visualParent': parentId, 'parents': folderStruct, }
data.update({'visualParent': parentId, 'parents': folderStruct})
folderStruct.append(asset['name'])
# Set custom attribute to avalon/mongo id of entity (parentID is last)
if custAttrName in entity['custom_attributes'] and entity['custom_attributes'][custAttrName] is '':
entity['custom_attributes'][custAttrName] = str(parentId)
io.uninstall()
def launch(self, session, entities, event):
""" JOB SETTING """
# JOB SETTINGS
userId = event['source']['user']['id']
user = session.query('User where id is ' + userId).one()
@ -134,7 +141,6 @@ class SyncToAvalon(BaseAction):
'data': json.dumps({
'description': 'Synch Ftrack to Avalon.'
})
})
try:
@ -142,7 +148,7 @@ class SyncToAvalon(BaseAction):
def getShotAsset(entity):
if not (entity.entity_type in ['Task']):
if not (entity in importable):
if entity not in importable:
importable.append(entity)
if entity['children']:
@ -150,37 +156,12 @@ class SyncToAvalon(BaseAction):
for child in childrens:
getShotAsset(child)
""" Get all Shots and AssetBuild from entities """
# get all entities separately
for entity in entities:
entity_type, entity_id = entity
act_ent = session.get(entity_type, entity_id)
getShotAsset(act_ent)
# _handle_result -> by to mel resit
# """ TODO Check if name of entities match REGEX"""
# for entity in importable:
# for e in entity['link']:
# item = {
# "silo": "silo",
# "parent": "parent",
# "type": "asset",
# "schema": "avalon-core:asset-2.0",
# "name": e['name'],
# "data": dict(),
# }
# try:
# schema.validate(item)
# except Exception as e:
# print(e)
# print(e['name'])
# ftrack.EVENT_HUB.publishReply(
# event,
# data={
# 'success': False,
# 'message': 'Entity name contains invalid character!'
# }
# )
for e in importable:
self.importToAvalon(session, e)

111
pype/ftrack/actions/test.py Normal file
View file

@ -0,0 +1,111 @@
# :coding: utf-8
# :copyright: Copyright (c) 2017 ftrack
import sys
import argparse
import logging
import collections
import os
import json
import ftrack_api
from ftrack_action_handler.action import BaseAction
from avalon import io, inventory, schema
from avalon.vendor import toml
class TestAction(BaseAction):
'''Edit meta data action.'''
#: Action identifier.
identifier = 'test.action'
#: Action label.
label = 'Test action'
#: Action description.
description = 'Test action'
def validate_selection(self, session, entities):
'''Return if *entities* is a valid selection.'''
# if (len(entities) != 1):
# # If entities contains more than one item return early since
# # metadata cannot be edited for several entites at the same time.
# return False
pass
# entity_type, entity_id = entities[0]
# if (
# entity_type not in session.types
# ):
# # Return False if the target entity does not have a metadata
# # attribute.
# return False
return True
def discover(self, session, entities, event):
'''Return True if action is valid.'''
self.logger.info('Got selection: {0}'.format(entities))
return self.validate_selection(session, entities)
def launch(self, session, entities, event):
""" JOB SETTING """
return True
def register(session, **kw):
'''Register plugin. Called when used as an plugin.'''
# Validate that session is an instance of ftrack_api.Session. If not,
# assume that register is being called from an old or incompatible API and
# return without doing anything.
if not isinstance(session, ftrack_api.session.Session):
return
action_handler = TestAction(session)
action_handler.register()
def main(arguments=None):
'''Set up logging and register action.'''
if arguments is None:
arguments = []
parser = argparse.ArgumentParser()
# Allow setting of logging level from arguments.
loggingLevels = {}
for level in (
logging.NOTSET, logging.DEBUG, logging.INFO, logging.WARNING,
logging.ERROR, logging.CRITICAL
):
loggingLevels[logging.getLevelName(level).lower()] = level
parser.add_argument(
'-v', '--verbosity',
help='Set the logging output verbosity.',
choices=loggingLevels.keys(),
default='info'
)
namespace = parser.parse_args(arguments)
# Set up basic logging
logging.basicConfig(level=loggingLevels[namespace.verbosity])
session = ftrack_api.Session(
server_url="https://pype.ftrackapp.com",
api_key="4e01eda0-24b3-4451-8e01-70edc03286be",
api_user="jakub.trllo"
)
register(session)
# Wait for events
logging.info(
'Registered actions and listening for events. Use Ctrl-C to abort.'
)
session.event_hub.wait()
if __name__ == '__main__':
raise SystemExit(main(sys.argv[1:]))

126
pype/ftrack/ftrack_utils.py Normal file
View file

@ -0,0 +1,126 @@
# fttrack help functions
# import ftrack
import os
from pprint import *
def deleteAssetsForTask(taskId):
#taskId = os.environ['FTRACK_TASKID']
task = ftrack.Task(taskId)
taskAssets = task.getAssets()
print(taskAssets)
for a in taskAssets:
print(a.getName())
a.delete()
#shot = task.getParent()
#shotAssets = shot.getAssets()
def deleteAssetsFromShotByName(shotId, assNm=None):
if not assNm:
return
shot = ftrack.Task(shotId)
shotAssets = shot.getAssets()
for a in shotAssets:
nm = a.getName()
if nm == assNm:
a.delete()
def killRunningTasks(tm=None):
import datetime
import ftrack_api
session = ftrack_api.Session()
# Query all jobs created prior to yesterday which has not yet been completed.
yesterday = datetime.date.today() - datetime.timedelta(days=1)
if tm:
yesterday = tm
print(yesterday)
jobs = session.query(
'select id, status from Job '
'where status in ("queued", "running") and created_at > {0}'.format(yesterday)
)
# Update all the queried jobs, setting the status to failed.
for job in jobs:
print(job['created_at'])
print('Changing Job ({}) status: {} -> failed'.format(job['id'], job['status']))
job['status'] = 'failed'
session.commit()
print('Complete')
def createCustomAttr():
import ftrack_api
session = ftrack_api.Session()
objTypes = set() # for custom attribute creation
# TODO get all entity types ---- NOT TASK
# objTypes.add(session.query('ObjectType where name is ' + entity.entity_type).one())
# Name & Label for export Avalon-mongo ID to Ftrack
allCustAttr = session.query('CustomAttributeConfiguration').all()
curCustAttr = []
for ca in allCustAttr:
curCustAttr.append(ca['key'])
custAttrName = 'avalon_mongo_id'
custAttrLabel = 'Avalon/Mongo Id'
custAttrType = session.query('CustomAttributeType where name is "text"').one()
# TODO WHICH SECURITY ROLE IS RIGHT
custAttrSecuRole = session.query('SecurityRole').all()
for custAttrObjType in objTypes:
# custAttrObjType = session.query('ObjectType where name is ' + entity.entity_type).one()
# Create Custom attribute if not exists
if custAttrName not in curCustAttr:
session.create('CustomAttributeConfiguration', {
'entity_type': 'task',
'object_type_id': custAttrObjType['id'],
'type': custAttrType,
'label': custAttrLabel,
'key': custAttrName,
'default': '',
'write_security_roles': custAttrSecuRole,
'read_security_roles': custAttrSecuRole,
'config': json.dumps({'markdown': False}),
})
session.commit()
def checkRegex():
# _handle_result -> would be solution?
# """ TODO Check if name of entities match REGEX"""
for entity in importable:
for e in entity['link']:
item = {
"silo": "silo",
"parent": "parent",
"type": "asset",
"schema": "avalon-core:asset-2.0",
"name": e['name'],
"data": dict(),
}
try:
schema.validate(item)
except Exception as e:
print(e)
print(e['name'])
ftrack.EVENT_HUB.publishReply(
event,
data={
'success': False,
'message': 'Entity name contains invalid character!'
}
)