13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215 | class CreateProjectFolders(LocalAction):
"""Action create folder structure and may create hierarchy in ftrack.
Creation of folder structure and hierarchy in ftrack is based on settings.
Example of content:
```json
{
"__project_root__": {
"prod" : {},
"resources" : {
"footage": {
"plates": {},
"offline": {}
},
"audio": {},
"art_dept": {}
},
"editorial" : {},
"assets[ftrack.Library]": {
"characters[ftrack]": {},
"locations[ftrack]": {}
},
"shots[ftrack.Sequence]": {
"scripts": {},
"editorial[ftrack.Folder]": {}
}
}
}
```
Key "__project_root__" indicates root folder (or entity). Each key in
dictionary represents folder name. Value may contain another dictionary
with subfolders.
Identifier `[ftrack]` in name says that this should be also created in
ftrack hierarchy. It is possible to specify entity type of item with "." .
If key is `assets[ftrack.Library]` then in ftrack will be created entity
with name "assets" and entity type "Library". It is expected Library entity
type exist in ftrack.
"""
identifier = "ayon.create.project.structure"
label = "Create Project Structure"
description = "Creates folder structure"
role_list = ["Administrator", "Project Manager"]
icon = get_ftrack_icon_url("CreateProjectFolders.svg")
pattern_array = re.compile(r"\[.*\]")
pattern_ftrack = re.compile(r".*\[[.]*ftrack[.]*")
pattern_ent_ftrack = re.compile(r"ftrack\.[^.,\],\s,]*")
pattern_template = re.compile(r"\{.*\}")
project_root_key = "__project_root__"
def discover(self, session, entities, event):
if len(entities) != 1:
return False
if entities[0].entity_type.lower() != "project":
return False
return True
def launch(self, session, entities, event):
# Get project entity
project_entity = self.get_project_from_entity(entities[0])
project_name = project_entity["full_name"]
ayon_project = ayon_api.get_project(project_name)
if not ayon_project:
return {
"success": False,
"message": f"Project '{project_name}' was not found in AYON.",
}
try:
# Get paths based on presets
basic_paths = get_project_basic_paths(project_name)
if not basic_paths:
return {
"success": False,
"message": "Project structure is not set."
}
# Invoking AYON API to create the project folders
create_project_folders(project_name, basic_paths)
self.create_ftrack_entities(basic_paths, project_entity)
self.trigger_event(
"ayon.project.structure.created",
{"project_name": project_name}
)
except Exception as exc:
self.log.warning("Creating of structure crashed.", exc_info=True)
session.rollback()
return {
"success": False,
"message": str(exc)
}
return True
def get_ftrack_paths(self, paths_items):
all_ftrack_paths = []
for path_items in paths_items:
if not path_items:
continue
ftrack_path_items = []
is_ftrack = False
for item in reversed(path_items):
# QUESTION Why this not validated only on first item?
if (
item == self.project_root_key
# Fix to skip any formatting items (I don't like it!)
# - '{root[work]}' and '{project[name]}'
or self.pattern_template.match(item)
):
continue
if is_ftrack:
ftrack_path_items.append(item)
elif self.pattern_ftrack.match(item):
ftrack_path_items.append(item)
is_ftrack = True
ftrack_path_items = list(reversed(ftrack_path_items))
if ftrack_path_items:
all_ftrack_paths.append(ftrack_path_items)
return all_ftrack_paths
def compute_ftrack_items(self, in_list, keys):
if len(keys) == 0:
return in_list
key = keys[0]
exist = None
for index, subdict in enumerate(in_list):
if key in subdict:
exist = index
break
if exist is not None:
in_list[exist][key] = self.compute_ftrack_items(
in_list[exist][key], keys[1:]
)
else:
in_list.append({key: self.compute_ftrack_items([], keys[1:])})
return in_list
def translate_ftrack_items(self, paths_items):
main = []
for path_items in paths_items:
main = self.compute_ftrack_items(main, path_items)
return main
def create_ftrack_entities(self, basic_paths, project_ent):
only_ftrack_items = self.get_ftrack_paths(basic_paths)
ftrack_paths = self.translate_ftrack_items(only_ftrack_items)
for separation in ftrack_paths:
parent = project_ent
self.trigger_creation(separation, parent)
def trigger_creation(self, separation, parent):
for item, subvalues in separation.items():
matches = self.pattern_array.findall(item)
ent_type = "Folder"
if len(matches) == 0:
name = item
else:
match = matches[0]
name = item.replace(match, "")
ent_type_match = self.pattern_ent_ftrack.findall(match)
if len(ent_type_match) > 0:
ent_type_split = ent_type_match[0].split(".")
if len(ent_type_split) == 2:
ent_type = ent_type_split[1]
new_parent = self.create_ftrack_entity(name, ent_type, parent)
if subvalues:
for subvalue in subvalues:
self.trigger_creation(subvalue, new_parent)
def create_ftrack_entity(self, name, ent_type, parent):
for children in parent["children"]:
if children["name"] == name:
return children
data = {
"name": name,
"parent_id": parent["id"]
}
if parent.entity_type.lower() == "project":
data["project_id"] = parent["id"]
else:
data["project_id"] = parent["project"]["id"]
existing_entity = self.session.query((
"TypedContext where name is \"{}\" and "
"parent_id is \"{}\" and project_id is \"{}\""
).format(name, data["parent_id"], data["project_id"])).first()
if existing_entity:
return existing_entity
new_ent = self.session.create(ent_type, data)
self.session.commit()
return new_ent
|