def register_dcc_paths(dcc_paths=None):

    # Register DCC paths
    dccs_path = utils.force_list(dcc_paths)
    valid_dcc_paths = list()
    dcc_paths_str = ''
    default_dccs_path = os.path.join(
        os.path.dirname(os.path.abspath(__file__)), 'dccs')
    dccs_path.append(default_dccs_path)
    for dcc_path in dccs_path:
        if os.path.isdir(dcc_path):
            if dcc_path not in sys.path:
                sys.path.append(dcc_path)
            valid_dcc_paths.append(dcc_path)
    if valid_dcc_paths:
        if os.environ.get(consts.AED, None):
            env = os.environ[consts.AED].split(';')
            env.extend(valid_dcc_paths)
            clean_env = list(set([utils.clean_path(pth) for pth in env]))
            dcc_paths_str = ';'.join(clean_env)
        else:
            dcc_paths_str = ';'.join(valid_dcc_paths)
    if os.environ.get(consts.AED, ''):
        if dcc_paths_str:
            os.environ[consts.AED] += ';{}'.format(dcc_paths_str)
    else:
        os.environ[consts.AED] = dcc_paths_str
Exemple #2
0
def register_paths(plugin_paths):
    """
    Registers given path into the list of Artella plugin paths.
    :param str plugin_paths: Path that will be used by Artella Plugins Manager to search plugins into.
    """

    plugin_paths = utils.force_list(plugin_paths, remove_duplicates=True)

    for plugin_path in plugin_paths:
        plugin_path = utils.clean_path(plugin_path)
        if not plugin_path or not os.path.isdir(
                plugin_path) or plugin_path in _PLUGIN_PATHS:
            return

        _PLUGIN_PATHS.append(plugin_path)
def register_resources_path(resources_path):
    """
    Registers a path where resources will be searched
    :param str resources_path: Path to search resources in
    """

    if not resources_path or not os.path.isdir(resources_path):
        return

    resources_path = utils.clean_path(resources_path)
    if resources_path in _RESOURCES_PATHS:
        return

    _RESOURCES_PATHS.append(resources_path)

    dcc.register_dcc_resource_path(resources_path)
    icons_path = os.path.join(resources_path, 'icons')
    if os.path.isdir(icons_path):
        dcc.register_dcc_resource_path(icons_path)
Exemple #4
0
    def make_new_version(self, file_path=None, comment=None, do_lock=False):
        """
        Uploads a new file/folder or a new version of current opened DCC scene file

        :param str file_path: Optional path of the file we want to create new version of. If not given, current
            opened DCC scene file path will be used.
        :param str comment: Optional comment to add to new version metadata. If not given, a generic message will be
            used.
        :param bool do_lock: Whether or not to force the lock of the file to make a new version. With new Artella
            version this is not mandatory.
        :return: True if the make new version operation is completed successfully; False otherwise.
        :rtype: bool
        """

        artella_drive_client = self.get_client()
        if not artella_drive_client:
            return False

        if not file_path:
            file_path = dcc.scene_name()
            if not file_path:
                msg = 'Please open a file before creating a new version'
                logger.warning(msg)
                return False

        file_path = utils.clean_path(file_path)

        can_lock = artella_drive_client.can_lock_file(file_path=file_path)
        if not can_lock:
            msg = 'Unable to lock file to make new version. File is already locked by other user.'
            dcc.show_error('File already locked by other user', msg)
            logger.error(msg)
            return False

        version_created = True

        comment = str(comment) if comment else 'New file version'

        file_version = artella_drive_client.file_current_version(file_path)
        if file_version is None:
            self.show_warning_message('Unable to retrieve version from current scene')
            return False

        next_version = file_version + 1

        is_locked, _, _, _ = artella_drive_client.check_lock(file_path)
        if not is_locked and do_lock:
            valid_lock = self.lock_file()
            if not valid_lock:
                self.show_error_message('Unable to lock file to make new version ({})'.format(next_version))
                return False

        logger.info('Saving current scene: {}'.format(file_path))
        valid_save = dcc.save_scene()
        if not valid_save:
            self.show_error_message('Unable to save current scene: "{}"'.format(file_path))
            version_created = False
        else:
            uri_path = self.local_path_to_uri(file_path)
            rsp = artella_drive_client.upload(uri_path, comment=comment)
            if rsp.get('error'):
                msg = 'Unable to upload a new version of file: "{}"\n{}\n{}'.format(
                    os.path.basename(file_path), rsp.get('url'), rsp.get('error'))
                self.show_error_message(msg)
                version_created = False

        if not is_locked and do_lock:
            self.unlock_file(show_dialogs=False)

        return version_created
Exemple #5
0
def load_registered_plugins(dev=False):
    """
    Loads all the plugins found in the registered plugin paths
    :return:
    """

    plugin_paths = list(
        set([
            utils.clean_path(plugin_path) for plugin_path in _PLUGIN_PATHS
            if os.path.isdir(plugin_path)
        ]))
    if not plugin_paths:
        logger.info('No Artella Plugins found to load!')
        return

    found_paths = dict()

    for plugin_path in plugin_paths:
        for root, dirs, files in os.walk(plugin_path):
            if consts.ARTELLA_PLUGIN_CONFIG not in files:
                continue
            clean_path = utils.clean_path(root)
            found_paths[clean_path] = os.path.join(
                root, consts.ARTELLA_PLUGIN_CONFIG)

    if not found_paths:
        logger.info('No plugins found in registered plugin paths: {}'.format(
            _PLUGIN_PATHS))
        return

    for plugin_path in plugin_paths:
        for plugin_dir in os.listdir(plugin_path):
            clean_path = utils.clean_path(os.path.join(plugin_path,
                                                       plugin_dir))
            if os.path.isdir(clean_path) and clean_path not in sys.path:
                sys.path.append(clean_path)

    for plugin_path, plugin_config in found_paths.items():

        # Search sub modules paths
        sub_modules_found = list()
        for sub_module in utils.iterate_modules(plugin_path):
            file_name = os.path.splitext(os.path.basename(sub_module))[0]
            if file_name.startswith('_') or file_name.startswith(
                    'test_') or sub_module.endswith('.pyc'):
                continue
            if not sub_module or sub_module in sub_modules_found:
                continue
            sub_modules_found.append(sub_module)
        if not sub_modules_found:
            continue

        # Find specific DCC plugin implementation
        dcc_name = dcc.name()
        sub_module = sub_modules_found[0]

        max_length = 50
        index = 0
        artella_module_parts = list()
        temp_sub_module = sub_module
        while True:
            if index > max_length:
                artella_module_parts = list()
                break
            base_name = os.path.basename(temp_sub_module)
            if not base_name or base_name == 'artella':
                artella_module_parts.append(base_name)
                break
            artella_module_parts.append(base_name)
            temp_sub_module = os.path.dirname(temp_sub_module)
            index += 1
        if not artella_module_parts:
            module_path = utils.convert_module_path_to_dotted_path(
                os.path.normpath(sub_module))
        else:
            module_path = os.path.splitext('.'.join(
                reversed(artella_module_parts)))[0]

        module_path_split = module_path.split('.')
        dcc_module_path = '{}.{}.{}'.format('.'.join(module_path_split[:-1]),
                                            dcc_name, module_path_split[-1])
        sub_module_obj = utils.import_module(dcc_module_path,
                                             skip_exceptions=True)
        if not sub_module_obj:
            sub_module_obj = utils.import_module(module_path)
            if not sub_module_obj:
                logger.error(
                    'Error while importing Artella Plugin module: {}'.format(
                        module_path))
                continue

        if dev:
            plugin_version = 'DEV'
        else:
            plugin_version = None
            module_path_dir = module_path.rsplit('.', 1)[0]
            version_module_path = '{}.__version__'.format(module_path_dir)
            version_module_path = version_module_path.replace(
                '.{}.__'.format(dcc_name), '.__')
            try:
                version_module_obj = utils.import_module(version_module_path)
            except Exception:
                version_module_obj = None
            if version_module_obj:
                try:
                    plugin_version = version_module_obj.get_version()
                except Exception as exc:
                    logger.warning(
                        'Impossible to retrieve version for Artella Plugin module: {} | {}'
                        .format(module_path, exc))

        for member in utils.iterate_module_members(sub_module_obj,
                                                   predicate=inspect.isclass):
            register_plugin(member[1], plugin_config,
                            os.path.dirname(sub_module), plugin_version)

    if not _PLUGINS:
        logger.warning('No Artella plugins found to load!')
        return

    ordered_plugins_list = list()
    for plugin_id, plugin_dict in _PLUGINS.items():
        plugin_class = plugin_dict['class']
        plugin_index = plugin_class.INDEX or -1
        index = 0
        for i, plugin_item in enumerate(ordered_plugins_list):
            plugin_item_index = list(plugin_item.values())[0]['index']
            if plugin_index < plugin_item_index:
                index += 1
        ordered_plugins_list.insert(
            index, {plugin_id: {
                'index': plugin_index,
                'dict': plugin_dict
            }})

    for plugin_item in ordered_plugins_list:
        plugin_id = list(plugin_item.keys())[0]
        plugin_dict = list(plugin_item.values())[0]['dict']
        plugin_class = plugin_dict['class']
        plugin_config_dict = plugin_dict.get('config', dict())
        try:
            plugin_inst = plugin_class(plugin_config_dict)
        except Exception:
            logger.error(
                'Impossible to instantiate Artella Plugin: "{}"'.format(
                    plugin_id))
            logger.error(traceback.format_exc())
            continue
        _PLUGINS[plugin_id]['plugin_instance'] = plugin_inst
Exemple #6
0
    def uninstall(self, show_dialogs=True):
        artella_path = artella.__path__[0]
        if not os.path.isdir(artella_path):
            msg = 'Artella folder "{}" does not exists!'.format(artella_path)
            if show_dialogs:
                api.show_warning_message(text=msg)
            else:
                logger.warning(msg)
            return False

        res = qtutils.show_question_message_box(
            'Artella Uninstaller',
            'All plugins will be removed.\n\nArtella plugin will not be accessible by any DCC after uninstall.\n\n'
            'Are you sure you want to uninstall Artella Plugin?')
        if not res:
            return False

        do_remove_install_folder = not dccplugin.DccPlugin().dev

        valid_uninstall = self._uninstall(artella_path)
        if not valid_uninstall:
            msg = 'Artella uninstall process was not completed!'.format(artella_path)
            if show_dialogs:
                api.show_error_message(text=msg)
            else:
                logger.error(msg)
            return False

        loader.shutdown(dev=False)

        if do_remove_install_folder:
            try:
                logger.info('Removing Artella Dcc Plugin directory: {}'.format(artella_path))
                utils.delete_folder(artella_path)
            except Exception as exc:
                logger.warning(
                    'Impossible to remove Artella Dcc plugin directory: {} | {}'.format(artella_path, exc))
                return False

        if os.path.isdir(artella_path):
            msg = 'Artella folder was not removed during uninstall process.\n\n{}\n\n Remove it manually if you ' \
                  'want to have a complete clean uninstall of Artella plugin.'.format(artella_path)
            if show_dialogs:
                dcc.show_info('Artella Uninstaller', msg)
            else:
                logger.info(msg)
            utils.open_folder(os.path.dirname(artella_path))

        # Remove specific DCC install folder if exists
        root_dcc_install_dir = os.path.dirname(os.path.dirname(os.path.dirname(artella_path)))
        dcc_install_dir = os.path.join(root_dcc_install_dir, dcc.name())
        if os.path.isdir(dcc_install_dir):
            utils.delete_folder(dcc_install_dir)

        # Cleanup artella directories from
        artella_dir = os.path.dirname(artella_path)
        sys_paths = [artella_path, artella_dir, utils.clean_path(artella_path), utils.clean_path(artella_dir)]
        paths_to_remove = list()
        for sys_path in sys.path:
            if sys_path in sys_paths:
                paths_to_remove.append(sys_path)
                sys.path.remove(sys_path)
            elif 'artella-plugins' in sys_path or 'artella-dccs' in sys_path:
                paths_to_remove.append(sys_path)
        for path_to_remove in paths_to_remove:
            if path_to_remove not in sys.path:
                continue
            sys.path.remove(path_to_remove)

        return True
def current_dcc():
    """
    Returns the DCC loaded in current session for current environment
    If the current DCC is not already cached it will be automatically detected taking into account available DCC
    implementations. Otherwise, cached DCC is returned.

    :return: Name of the current used DCC
    :rtype: str
    """

    # If active DCC is already cache, we use it
    global CURRENT_DCC
    global CURRENT_DCC_MODULE
    if CURRENT_DCC:
        return CURRENT_DCC

    # If DCC is not available we make sure that we check all available dirs where DCC implementation can be located
    global DCCS_DIRS
    global DCCS
    dcc_paths_str = os.environ.get(consts.AED, '')
    if dcc_paths_str:
        dcc_paths_split = [
            utils.clean_path(pth) for pth in dcc_paths_str.split(';')
        ]
        for dcc_path in dcc_paths_split:
            if not dcc_path or not os.path.isdir(
                    dcc_path) or dcc_path in DCCS_DIRS:
                continue
            DCCS_DIRS.append(dcc_path)
    if DCCS_DIRS:
        for dcc_dir in DCCS_DIRS:
            for dcc_folder in os.listdir(dcc_dir):
                if not dcc_folder.startswith('__') and not dcc_folder.endswith(
                        '__') and dcc_folder != 'abstract':
                    DCCS[dcc_folder] = utils.clean_path(
                        os.path.join(dcc_dir, dcc_folder))
                    if DCCS[dcc_folder] not in sys.path:
                        sys.path.append(DCCS[dcc_folder])

    # Make sure standalone DCC is the last one checked
    dcc_names = list(DCCS.keys())
    standalone_names = [
        dcc_name for dcc_name in dcc_names if 'standalone' in dcc_name
    ]
    for standalone_name in standalone_names:
        dcc_names.pop(dcc_names.index(standalone_name))
        dcc_names.append(standalone_name)

    # Loop through all available DCCs and check which one is available in current session
    for dcc_name in dcc_names:
        dcc_namespace_split = dcc_name.split('-')
        dcc_names = [dcc_name, dcc_namespace_split[-1]
                     ] if dcc_namespace_split else [dcc_name]
        for dcc in dcc_names:
            if dcc.startswith('artella'):
                continue
            try:
                dcc_module_name = '{}.{}'.format(consts.ARTELLA_DCCS_NAMESPACE,
                                                 dcc)
                import_module(dcc_module_name)
                CURRENT_DCC = dcc
                CURRENT_DCC_MODULE = dcc_module_name
                logger.info('Current DCC: {}'.format(CURRENT_DCC))
                return CURRENT_DCC
            except ImportError as exc:
                continue