Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion avalon/io.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,9 @@ def _from_environment():
session = {
item[0]: os.getenv(item[0], item[1])
for item in (
# The schema name that should be used to validate this session
("AVALON_SESSION_SCHEMA", "avalon-core:session-2.0"),

# Root directory of projects on disk
("AVALON_PROJECTS", None),

Expand All @@ -132,6 +135,9 @@ def _from_environment():
# Name of current app
("AVALON_APP", None),

# Full name of current app (e.g. versioned name)
("AVALON_APP_NAME", None),

# Path to working directory
("AVALON_WORKDIR", None),

Expand Down Expand Up @@ -199,7 +205,7 @@ def _from_environment():
) if os.getenv(item[0], item[1]) is not None
}

session["schema"] = "avalon-core:session-2.0"
session["schema"] = session["AVALON_SESSION_SCHEMA"]
try:
schema.validate(session)
except schema.ValidationError as e:
Expand Down
11 changes: 9 additions & 2 deletions avalon/maya/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,15 @@

def reset_frame_range():
"""Set frame range to current asset"""
shot = api.Session["AVALON_ASSET"]
shot = io.find_one({"name": shot, "type": "asset"})
shot_name = api.Session.get("AVALON_ASSET")
if shot_name is None:
cmds.warning("No AVALON_ASSET setup in current working session.")
return

shot = io.find_one({"name": shot_name, "type": "asset"})
if shot is None:
cmds.error("Shot '%s' not found in database." % shot_name)
return

try:

Expand Down
8 changes: 4 additions & 4 deletions avalon/maya/pipeline.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,8 +125,8 @@ def deferred():

# Create context menu
context_label = "{}, {}".format(
api.Session["AVALON_ASSET"],
api.Session["AVALON_TASK"]
api.Session.get("AVALON_ASSET", "--"),
api.Session.get("AVALON_TASK", "--")
)

cmds.menuItem(
Expand Down Expand Up @@ -275,8 +275,8 @@ def _update_menu_task_label():
logger.warning("Can't find menuItem: {}".format(object_name))
return

label = "{}, {}".format(api.Session["AVALON_ASSET"],
api.Session["AVALON_TASK"])
label = "{}, {}".format(api.Session.get("AVALON_ASSET", "--"),
api.Session.get("AVALON_TASK", "--"))
cmds.menuItem(object_name, edit=True, label=label)


Expand Down
10 changes: 9 additions & 1 deletion avalon/nuke/command.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,16 @@ def reset_frame_range():
fps = float(api.Session.get("AVALON_FPS", 25))

nuke.root()["fps"].setValue(fps)
name = api.Session["AVALON_ASSET"]
name = api.Session.get("AVALON_ASSET")
if name is None:
log.warning("No AVALON_ASSET setup in current working session.")
return

asset = io.find_one({"name": name, "type": "asset"})
if asset is None:
log.error("No AVALON_ASSET setup in current working session.")
return

asset_data = asset["data"]

handles = get_handles(asset)
Expand Down
3 changes: 2 additions & 1 deletion avalon/nuke/pipeline.py
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,8 @@ def _install_menu():
menu = menubar.addMenu(api.Session["AVALON_LABEL"])

label = "{0}, {1}".format(
api.Session["AVALON_ASSET"], api.Session["AVALON_TASK"]
api.Session.get("AVALON_ASSET", "--"),
api.Session.get("AVALON_TASK", "--")
)
context_action = menu.addCommand(label)
context_action.setEnabled(False)
Expand Down
91 changes: 67 additions & 24 deletions avalon/pipeline.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ def install(host):
io.install()

missing = list()
for key in ("AVALON_PROJECT", "AVALON_ASSET"):
for key in ("AVALON_PROJECT", ):
if key not in Session:
missing.append(key)

Expand All @@ -72,6 +72,11 @@ def install(host):
project = Session["AVALON_PROJECT"]
log.info("Activating %s.." % project)

if not os.getenv("_AVALON_APP_INITIALIZED"):
log.info("Initializing working directory..")
no_predefined_workdir = "AVALON_WORKDIR" not in Session
initialize(Session, reset_workdir=no_predefined_workdir)

config = find_config()

# Optional host install function
Expand All @@ -94,6 +99,35 @@ def install(host):
log.info("Successfully installed Avalon!")


def initialize(session, reset_workdir):
"""Initialize Work Directory

This finds the current AVALON_APP_NAME and tries to triggers its
`.toml` initialization step. Note that this will only be valid
whenever `AVALON_APP_NAME` is actually set in the current session.

"""
# Find the application definition
app_name = session.get("AVALON_APP_NAME")
if not app_name:
log.error("No AVALON_APP_NAME session variable is set. "
"Unable to initialize app Work Directory.")
return

app_definition = lib.get_application(app_name)
App = type(
"app_%s" % app_name,
(Application,),
{
"name": app_name,
"config": app_definition.copy()
}
)
app = App()
env = app.environ(session, reset_workdir)
app.initialize(env)


def find_config():
log.info("Finding configuration for project..")

Expand Down Expand Up @@ -344,18 +378,19 @@ def is_compatible(self, session):
return False
return True

def environ(self, session):
def environ(self, session, reset_workdir=True):
"""Build application environment"""

session = session.copy()
session["AVALON_APP"] = self.config["application_dir"]
session["AVALON_APP_NAME"] = self.name

# Compute work directory
project = io.find_one({"type": "project"})
template = project["config"]["template"]["work"]
workdir = _format_work_template(template, session)
session["AVALON_WORKDIR"] = os.path.normpath(workdir)
if reset_workdir:
project = io.find_one({"type": "project"})
template = project["config"]["template"]["work"]
workdir = _format_work_template(template, session)
session["AVALON_WORKDIR"] = os.path.normpath(workdir)

# Construct application environment from .toml config
app_environment = self.config.get("environment", {})
Expand Down Expand Up @@ -391,39 +426,42 @@ def initialize(self, environment):
workdir = environment["AVALON_WORKDIR"]
workdir_existed = os.path.exists(workdir)
if not workdir_existed:
os.makedirs(workdir)
self.log.info("Creating working directory '%s'" % workdir)
os.makedirs(workdir)

# Create default directories from app configuration
default_dirs = self.config.get("default_dirs", [])
default_dirs = self._format(default_dirs, **environment)
if default_dirs:
self.log.debug("Creating default directories..")
for dirname in default_dirs:
try:
os.makedirs(os.path.join(workdir, dirname))
self.log.debug(" - %s" % dirname)
except OSError as e:
# An already existing default directory is fine.
if e.errno == errno.EEXIST:
pass
else:
raise
# Create default directories from app configuration
default_dirs = self.config.get("default_dirs", [])
default_dirs = self._format(default_dirs, **environment)
if default_dirs:
self.log.debug("Creating default directories..")
for dirname in default_dirs:
try:
os.makedirs(os.path.join(workdir, dirname))
self.log.debug(" - %s" % dirname)
except OSError as e:
# An already existing default directory is fine.
if e.errno == errno.EEXIST:
pass
else:
raise

# Perform application copy
for src, dst in self.config.get("copy", {}).items():
dst = os.path.join(workdir, dst)
# Expand env vars
src, dst = self._format([src, dst], **environment)

if os.path.isfile(dst):
continue

try:
self.log.info("Copying %s -> %s" % (src, dst))
shutil.copy(src, dst)
except OSError as e:
self.log.error("Could not copy application file: %s" % e)
self.log.error(" - %s -> %s" % (src, dst))

def launch(self, environment):
def launch(self, environment, initialized=False):

executable = lib.which(self.config["executable"])
if executable is None:
Expand All @@ -432,6 +470,9 @@ def launch(self, environment):
% (self.config["executable"], os.getenv("PATH"))
)

if initialized:
environment["_AVALON_APP_INITIALIZED"] = "1"

args = self.config.get("args", [])
return lib.launch(
executable=executable,
Expand All @@ -444,12 +485,14 @@ def process(self, session, **kwargs):
"""Process the full Application action"""

environment = self.environ(session)
initialized = False

if kwargs.get("initialize", True):
self.initialize(environment)
initialized = True

if kwargs.get("launch", True):
return self.launch(environment)
return self.launch(environment, initialized)

def _format(self, original, **kwargs):
"""Utility recursive dict formatting that logs the error clearly."""
Expand Down
Loading