getavalon / launcher

Environment management platform
MIT License
20 stars 22 forks source link

Separate controller.launch functionality into library functionality #20

Open BigRoy opened 7 years ago

BigRoy commented 7 years ago

Issue

Currently the only way in Avalon to set up a project's environment is to actually launch into the application through the Launcher. I believe this should be simplified and separated so that it becomes trivial to initialize an application's environment for an asset in code, e.g. when trying to batch prepare a lot of assets.

This would also increase the readability of launching an application itself, since it would just rely on the library functions for initializing the environment, like lib.create_environment(asset, task, app).

This is not reliable pseudocode, but would present the idea.

# pseudocode
import os
import errno
import traceback
import shutil
from avalon import io

# A mockup maya application (should be loaded from .toml)
app = {
    "default_dirs": [
        "scenes",
        "data",
        "renderData/shaders",
        "images",
        "sourceimages"
    ],
    "copy": {
        "{AVALON_CORE}/res/workspace.mel": "workspace.mel"
    }
}

asset = io.find_one({"type": "asset"})
create_environment(app, asset, task="model")

def create_environment(app, asset, task):
    """Create a work environment for application in asset's task.

    Arguments:
        app (dict): Application specification.
        asset (bson.ObjectID): The asset database id.
        task (str): The name of the task to operate in.

    """
    # todo: actually get the workdir using project's config and the asset itself
    # this would format the template for "work" files.
    workdir = _get_workdir(asset, task, app)

    try:
        os.makedirs(workdir)
        log.info("Creating working directory '%s'", workdir)

    except OSError as e:

        # An already existing working directory is fine.
        if e.errno == errno.EEXIST:
            log.info("Existing working directory found.")

        else:
            log.error("Could not create working directory.")
            log.error(traceback.format_exc())

    else:
        log.info("Creating default directories..")
        for dirname in app.get("default_dirs", []):
            log.debug(" - %s",  dirname)
            os.makedirs(os.path.join(workdir, dirname))

    # Perform application copy
    for src, dst in app.get("copy", {}).items():
        # Format source by environment
        # TODO: Formatting shouldn't be done here!
        src = src.format(**os.environ)
        dst = os.path.join(workdir, dst)

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

I might even want to propose to have this logic be part of the avalon's core API, which would also make it an issue for avalon core.

mottosso commented 7 years ago

Thanks @BigRoy.

I also had some thoughts on this, where the (new and unused) Session object would carry a launch() method, launching a given application within the Session.

BigRoy commented 7 years ago

I also had some thoughts on this, where the (new and unused) Session object would carry a launch() method, launching a given application within the Session.

Sounds interesting! :)