コード例 #1
0
ファイル: pypeLauncher.py プロジェクト: tokejepsen/pype-setup
    def _load_default_environments(self, tools):
        """Load and apply default environment files."""
        import acre
        os.environ['PLATFORM'] = platform.system().lower()
        tools_env = acre.get_tools(tools)
        pype_paths_env = dict()
        for key, value in dict(os.environ).items():
            if key.startswith('PYPE_'):
                pype_paths_env[key] = value

        env = acre.append(tools_env, pype_paths_env)
        env = acre.compute(env, cleanup=True)
        os.environ = acre.append(dict(os.environ), env)
        os.environ = acre.compute(os.environ, cleanup=False)
コード例 #2
0
ファイル: env_tools.py プロジェクト: 3dzayn/pype
def get_global_environments(env=None):
    """Load global environments from Pype.

    Return prepared and parsed global environments by pype's settings. Use
    combination of "global" environments set in pype's settings and enabled
    modules.

    Args:
        env (dict, optional): Initial environments. Empty dictionary is used
            when not entered.

    Returns;
        dict of str: Loaded and processed environments.

    """
    import acre
    from openpype.modules import ModulesManager

    if env is None:
        env = {}

    # Get global environments from settings
    all_settings_env = get_environments()
    parsed_global_env = acre.parse(all_settings_env["global"])

    # Merge with entered environments
    merged_env = acre.append(env, parsed_global_env)

    # Get environments from Pype modules
    modules_manager = ModulesManager()

    module_envs = modules_manager.collect_global_environments()
    publish_plugin_dirs = modules_manager.collect_plugin_paths()["publish"]

    # Set pyblish plugins paths if any module want to register them
    if publish_plugin_dirs:
        publish_paths_str = os.environ.get("PYBLISHPLUGINPATH") or ""
        publish_paths = publish_paths_str.split(os.pathsep)
        _publish_paths = {
            os.path.normpath(path)
            for path in publish_paths if path
        }
        for path in publish_plugin_dirs:
            _publish_paths.add(os.path.normpath(path))
        module_envs["PYBLISHPLUGINPATH"] = os.pathsep.join(_publish_paths)

    # Merge environments with current environments and update values
    if module_envs:
        parsed_envs = acre.parse(module_envs)
        merged_env = acre.merge(parsed_envs, merged_env)

    return acre.compute(merged_env, cleanup=True)
コード例 #3
0
    def test_append(self):
        """Append paths of two environments into one."""

        data_a = {"A": "A", "B": "B"}
        data_b = {"A": "A2", "C": "C2"}

        # Keep unaltered copies to check afterwards the originals
        # remain unaltered by the append function
        _data_a = data_a.copy()
        _data_b = data_b.copy()

        data = acre.append(data_a, data_b)

        self.assertEqual(data, {"A": "A;A2", "B": "B", "C": "C2"})

        # Ensure the original dicts are unaltered
        self.assertEqual(data_a, _data_a)
        self.assertEqual(data_b, _data_b)
コード例 #4
0
    def launch(self, session, entities, event):
        '''Callback method for the custom action.

        return either a bool ( True if successful or False if the action failed )
        or a dictionary with they keys `message` and `success`, the message should be a
        string and will be displayed as feedback to the user, success should be a bool,
        True if successful or False if the action failed.

        *session* is a `ftrack_api.Session` instance

        *entities* is a list of tuples each containing the entity type and the entity id.
        If the entity is a hierarchical you will always get the entity
        type TypedContext, once retrieved through a get operation you
        will have the "real" entity type ie. example Shot, Sequence
        or Asset Build.

        *event* the unmodified original event

        '''

        entity = entities[0]
        project_name = entity['project']['full_name']

        database = pypelib.get_avalon_database()

        # Get current environments
        env_list = [
            'AVALON_PROJECT', 'AVALON_SILO', 'AVALON_ASSET', 'AVALON_TASK',
            'AVALON_APP', 'AVALON_APP_NAME'
        ]
        env_origin = {}
        for env in env_list:
            env_origin[env] = os.environ.get(env, None)

        # set environments for Avalon
        os.environ["AVALON_PROJECT"] = project_name
        os.environ["AVALON_SILO"] = entity['ancestors'][0]['name']
        os.environ["AVALON_ASSET"] = entity['parent']['name']
        os.environ["AVALON_TASK"] = entity['name']
        os.environ["AVALON_APP"] = self.identifier.split("_")[0]
        os.environ["AVALON_APP_NAME"] = self.identifier

        anatomy = Anatomy()

        hierarchy = ""
        parents = database[project_name].find_one({
            "type":
            'asset',
            "name":
            entity['parent']['name']
        })['data']['parents']

        if parents:
            hierarchy = os.path.join(*parents)

        application = avalonlib.get_application(os.environ["AVALON_APP_NAME"])

        data = {
            "root": os.environ.get("PYPE_STUDIO_PROJECTS_MOUNT"),
            "project": {
                "name": entity['project']['full_name'],
                "code": entity['project']['name']
            },
            "task": entity['name'],
            "asset": entity['parent']['name'],
            "app": application["application_dir"],
            "hierarchy": hierarchy,
        }

        av_project = database[project_name].find_one({"type": 'project'})
        templates = None
        if av_project:
            work_template = av_project.get('config',
                                           {}).get('template',
                                                   {}).get('work', None)
        work_template = None
        try:
            work_template = work_template.format(**data)
        except Exception:
            try:
                anatomy = anatomy.format(data)
                work_template = anatomy["work"]["folder"]

            except Exception as exc:
                msg = "{} Error in anatomy.format: {}".format(
                    __name__, str(exc))
                self.log.error(msg, exc_info=True)
                return {'success': False, 'message': msg}

        workdir = os.path.normpath(work_template)
        os.environ["AVALON_WORKDIR"] = workdir
        try:
            os.makedirs(workdir)
        except FileExistsError:
            pass

        # collect all parents from the task
        parents = []
        for item in entity['link']:
            parents.append(session.get(item['type'], item['id']))

        # collect all the 'environment' attributes from parents
        tools_attr = [os.environ["AVALON_APP"], os.environ["AVALON_APP_NAME"]]
        for parent in reversed(parents):
            # check if the attribute is empty, if not use it
            if parent['custom_attributes']['tools_env']:
                tools_attr.extend(parent['custom_attributes']['tools_env'])
                break

        tools_env = acre.get_tools(tools_attr)
        env = acre.compute(tools_env)
        env = acre.merge(env, current_env=dict(os.environ))
        env = acre.append(dict(os.environ), env)

        #
        # tools_env = acre.get_tools(tools)
        # env = acre.compute(dict(tools_env))
        # env = acre.merge(env, dict(os.environ))
        # os.environ = acre.append(dict(os.environ), env)
        # os.environ = acre.compute(os.environ)

        # Get path to execute
        st_temp_path = os.environ['PYPE_CONFIG']
        os_plat = platform.system().lower()

        # Path to folder with launchers
        path = os.path.join(st_temp_path, 'launchers', os_plat)
        # Full path to executable launcher
        execfile = None

        if sys.platform == "win32":

            for ext in os.environ["PATHEXT"].split(os.pathsep):
                fpath = os.path.join(path.strip('"'), self.executable + ext)
                if os.path.isfile(fpath) and os.access(fpath, os.X_OK):
                    execfile = fpath
                    break
                pass

            # Run SW if was found executable
            if execfile is not None:
                avalonlib.launch(executable=execfile, args=[], environment=env)
            else:
                return {
                    'success':
                    False,
                    'message':
                    "We didn't found launcher for {0}".format(self.label)
                }
                pass

        if sys.platform.startswith('linux'):
            execfile = os.path.join(path.strip('"'), self.executable)
            if os.path.isfile(execfile):
                try:
                    fp = open(execfile)
                except PermissionError as p:
                    self.log.exception('Access denied on {0} - {1}'.format(
                        execfile, p))
                    return {
                        'success':
                        False,
                        'message':
                        "Access denied on launcher - {}".format(execfile)
                    }
                fp.close()
                # check executable permission
                if not os.access(execfile, os.X_OK):
                    self.log.error(
                        'No executable permission on {}'.format(execfile))
                    return {
                        'success': False,
                        'message':
                        "No executable permission - {}".format(execfile)
                    }
                    pass
            else:
                self.log.error('Launcher doesn\'t exist - {}'.format(execfile))
                return {
                    'success': False,
                    'message': "Launcher doesn't exist - {}".format(execfile)
                }
                pass
            # Run SW if was found executable
            if execfile is not None:
                avalonlib.launch('/usr/bin/env',
                                 args=['bash', execfile],
                                 environment=env)
            else:
                return {
                    'success':
                    False,
                    'message':
                    "We didn't found launcher for {0}".format(self.label)
                }
                pass

        # Change status of task to In progress
        presets = config.get_presets()["ftrack"]["ftrack_config"]

        if 'status_update' in presets:
            statuses = presets['status_update']

            actual_status = entity['status']['name'].lower()
            next_status_name = None
            for key, value in statuses.items():
                if actual_status in value or '_any_' in value:
                    if key != '_ignore_':
                        next_status_name = key
                    break

            if next_status_name is not None:
                try:
                    query = 'Status where name is "{}"'.format(
                        next_status_name)
                    status = session.query(query).one()
                    entity['status'] = status
                    session.commit()
                except Exception:
                    msg = ('Status "{}" in presets wasn\'t found on Ftrack'
                           ).format(next_status_name)
                    self.log.warning(msg)

        # Set origin avalon environments
        for key, value in env_origin.items():
            if value == None:
                value = ""
            os.environ[key] = value

        return {'success': True, 'message': "Launching {0}".format(self.label)}
コード例 #5
0
    def launch(self, session, entities, event):
        """Callback method for the custom action.

        return either a bool (True if successful or False if the action failed)
        or a dictionary with they keys `message` and `success`, the message
        should be a string and will be displayed as feedback to the user,
        success should be a bool, True if successful or False if the action
        failed.

        *session* is a `ftrack_api.Session` instance

        *entities* is a list of tuples each containing the entity type and
        the entity id. If the entity is a hierarchical you will always get
        the entity type TypedContext, once retrieved through a get operation
        you will have the "real" entity type ie. example Shot, Sequence
        or Asset Build.

        *event* the unmodified original event
        """

        entity = entities[0]
        project_name = entity["project"]["full_name"]

        database = pypelib.get_avalon_database()

        asset_name = entity["parent"]["name"]
        asset_document = database[project_name].find_one({
            "type": "asset",
            "name": asset_name
        })

        hierarchy = ""
        asset_doc_parents = asset_document["data"].get("parents")
        if len(asset_doc_parents) > 0:
            hierarchy = os.path.join(*asset_doc_parents)

        application = avalon.lib.get_application(self.identifier)
        data = {
            "project": {
                "name": entity["project"]["full_name"],
                "code": entity["project"]["name"]
            },
            "task": entity["name"],
            "asset": asset_name,
            "app": application["application_dir"],
            "hierarchy": hierarchy
        }

        try:
            anatomy = Anatomy(project_name)
            anatomy_filled = anatomy.format(data)
            workdir = os.path.normpath(anatomy_filled["work"]["folder"])

        except Exception as exc:
            msg = "Error in anatomy.format: {}".format(str(exc))
            self.log.error(msg, exc_info=True)
            return {"success": False, "message": msg}

        try:
            os.makedirs(workdir)
        except FileExistsError:
            pass

        # set environments for Avalon
        prep_env = copy.deepcopy(os.environ)
        prep_env.update({
            "AVALON_PROJECT": project_name,
            "AVALON_ASSET": asset_name,
            "AVALON_TASK": entity["name"],
            "AVALON_APP": self.identifier.split("_")[0],
            "AVALON_APP_NAME": self.identifier,
            "AVALON_HIERARCHY": hierarchy,
            "AVALON_WORKDIR": workdir
        })
        prep_env.update(anatomy.roots_obj.root_environments())

        # collect all parents from the task
        parents = []
        for item in entity['link']:
            parents.append(session.get(item['type'], item['id']))

        # collect all the 'environment' attributes from parents
        tools_attr = [prep_env["AVALON_APP"], prep_env["AVALON_APP_NAME"]]
        tools_env = asset_document["data"].get("tools_env") or []
        tools_attr.extend(tools_env)

        tools_env = acre.get_tools(tools_attr)
        env = acre.compute(tools_env)
        env = acre.merge(env, current_env=dict(prep_env))
        env = acre.append(dict(prep_env), env)

        # Get path to execute
        st_temp_path = os.environ["PYPE_CONFIG"]
        os_plat = platform.system().lower()

        # Path to folder with launchers
        path = os.path.join(st_temp_path, "launchers", os_plat)

        # Full path to executable launcher
        execfile = None

        if application.get("launch_hook"):
            hook = application.get("launch_hook")
            self.log.info("launching hook: {}".format(hook))
            ret_val = pypelib.execute_hook(application.get("launch_hook"),
                                           env=env)
            if not ret_val:
                return {
                    'success':
                    False,
                    'message':
                    "Hook didn't finish successfully {0}".format(self.label)
                }

        if sys.platform == "win32":
            for ext in os.environ["PATHEXT"].split(os.pathsep):
                fpath = os.path.join(path.strip('"'), self.executable + ext)
                if os.path.isfile(fpath) and os.access(fpath, os.X_OK):
                    execfile = fpath
                    break

            # Run SW if was found executable
            if execfile is None:
                return {
                    "success": False,
                    "message":
                    "We didn't find launcher for {0}".format(self.label)
                }

            popen = avalon.lib.launch(executable=execfile,
                                      args=[],
                                      environment=env)

        elif (sys.platform.startswith("linux")
              or sys.platform.startswith("darwin")):
            execfile = os.path.join(path.strip('"'), self.executable)
            if not os.path.isfile(execfile):
                msg = "Launcher doesn't exist - {}".format(execfile)

                self.log.error(msg)
                return {"success": False, "message": msg}

            try:
                fp = open(execfile)
            except PermissionError as perm_exc:
                msg = "Access denied on launcher {} - {}".format(
                    execfile, perm_exc)

                self.log.exception(msg, exc_info=True)
                return {"success": False, "message": msg}

            fp.close()
            # check executable permission
            if not os.access(execfile, os.X_OK):
                msg = "No executable permission - {}".format(execfile)

                self.log.error(msg)
                return {"success": False, "message": msg}

            # Run SW if was found executable
            if execfile is None:
                return {
                    "success":
                    False,
                    "message":
                    "We didn't found launcher for {0}".format(self.label)
                }

            popen = avalon.lib.launch(  # noqa: F841
                "/usr/bin/env",
                args=["bash", execfile],
                environment=env)

        # Change status of task to In progress
        presets = config.get_presets()["ftrack"]["ftrack_config"]

        if "status_update" in presets:
            statuses = presets["status_update"]

            actual_status = entity["status"]["name"].lower()
            already_tested = []
            ent_path = "/".join([ent["name"] for ent in entity["link"]])
            while True:
                next_status_name = None
                for key, value in statuses.items():
                    if key in already_tested:
                        continue
                    if actual_status in value or "_any_" in value:
                        if key != "_ignore_":
                            next_status_name = key
                            already_tested.append(key)
                        break
                    already_tested.append(key)

                if next_status_name is None:
                    break

                try:
                    query = "Status where name is \"{}\"".format(
                        next_status_name)
                    status = session.query(query).one()

                    entity["status"] = status
                    session.commit()
                    self.log.debug("Changing status to \"{}\" <{}>".format(
                        next_status_name, ent_path))
                    break

                except Exception:
                    session.rollback()
                    msg = ("Status \"{}\" in presets wasn't found"
                           " on Ftrack entity type \"{}\"").format(
                               next_status_name, entity.entity_type)
                    self.log.warning(msg)

        return {"success": True, "message": "Launching {0}".format(self.label)}