mirror of
https://github.com/ynput/ayon-core.git
synced 2026-01-01 08:24:53 +01:00
Added feature for set MongoId to Ftrack
This commit is contained in:
parent
2ae76c2d5b
commit
f56fdc0700
4 changed files with 383 additions and 38 deletions
127
pype/ftrack/actions/action_killRunningJobs.py
Normal file
127
pype/ftrack/actions/action_killRunningJobs.py
Normal 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:]))
|
||||
|
|
@ -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
111
pype/ftrack/actions/test.py
Normal 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
126
pype/ftrack/ftrack_utils.py
Normal 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!'
|
||||
}
|
||||
)
|
||||
Loading…
Add table
Add a link
Reference in a new issue