From f7797a90f6ffc5db9ae227a6398f72b34af241e6 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Thu, 6 Jun 2024 15:28:44 +0200 Subject: [PATCH] Core: Make BLENDER_SYSTEM_SCRIPTS always add paths Originally this would replace scripts that come bundled with Blender, but it's unclear how this is useful. Searching for this online mainly leads to people asking how they can use it to add scripts. For example in a studio environment you might want to deploy add-ons and startup scripts for all users. Even if you wanted to use it for replacement though, it wasn't really doing that and inconsistent for different types of scripts: * startup: ignored * modules: replaces bundled scripts * presets: adds to bundled scripts * addons (in 4.1): ignored * addons_core (in 4.2): ignored * startup/bl_app_templates_system: replaces bundled scripts This change makes it add scripts from this path for all. This is a breaking change, though arguably this feature was just broken to begin with and not used much in practice because of that. The alternative would be add a new set of environment variables to avoid breaking existing behavior. But that also means keeping around the broken behavior or fixing it in another way. Supporting multiple paths may be used too, but for now just support a single one as doing this for all BLENDER_SYSTEM variables is non-trivial. The main use case for that would be add-ons anyway, and those will mainly be handled through upcoming BLENDER_SYSTEM_EXTENSIONS instead. Ref #122512 Pull Request: https://projects.blender.org/blender/blender/pulls/122689 --- scripts/modules/bpy/utils/__init__.py | 39 +++++++--- source/blender/blenkernel/intern/appdir.cc | 87 ++++++++++++---------- source/creator/creator_args.cc | 13 ++-- 3 files changed, 81 insertions(+), 58 deletions(-) diff --git a/scripts/modules/bpy/utils/__init__.py b/scripts/modules/bpy/utils/__init__.py index 820b5b59f72..df34316c94d 100644 --- a/scripts/modules/bpy/utils/__init__.py +++ b/scripts/modules/bpy/utils/__init__.py @@ -378,7 +378,13 @@ def script_paths_pref(): return paths -def script_paths(*, subdir=None, user_pref=True, check_all=False, use_user=True): +def script_paths_system_environment(): + """Returns a list of system script directories from environment variables.""" + if env_system_path := _os.environ.get("BLENDER_SYSTEM_SCRIPTS"): + return [_os.path.normpath(env_system_path)] + return [] + +def script_paths(*, subdir=None, user_pref=True, check_all=False, use_user=True, use_system_environment=True): """ Returns a list of valid script paths. @@ -388,6 +394,10 @@ def script_paths(*, subdir=None, user_pref=True, check_all=False, use_user=True) :type user_pref: bool :arg check_all: Include local, user and system paths rather just the paths Blender uses. :type check_all: bool + :arg use_user: Include user paths + :type use_user: bool + :arg use_system_environment: Include BLENDER_SYSTEM_SCRIPTS variable path + :type use_system_environment: bool :return: script paths. :rtype: list """ @@ -419,6 +429,9 @@ def script_paths(*, subdir=None, user_pref=True, check_all=False, use_user=True) if user_pref: base_paths.extend(script_paths_pref()) + if use_system_environment: + base_paths.extend(script_paths_system_environment()) + scripts = [] for path in base_paths: if not path: @@ -473,16 +486,22 @@ def app_template_paths(*, path=None): """ subdir_args = (path,) if path is not None else () # Note: keep in sync with: Blender's 'BKE_appdir_app_template_any'. - # Uses 'BLENDER_USER_SCRIPTS', 'BLENDER_SYSTEM_SCRIPTS' - # ... in this case 'system' accounts for 'local' too. - for resource_fn, module_name in ( - (_user_resource, "bl_app_templates_user"), - (system_resource, "bl_app_templates_system"), - ): - path_test = resource_fn('SCRIPTS', path=_os.path.join("startup", module_name, *subdir_args)) - if path_test and _os.path.isdir(path_test): + # Uses BLENDER_USER_SCRIPTS + path_test = _user_resource('SCRIPTS', path=_os.path.join("startup", "bl_app_templates_user", *subdir_args)) + if path_test and _os.path.isdir(path_test): + yield path_test + + # Uses BLENDER_SYSTTEM_SCRIPTS + for path in script_paths_system_environment(): + path_test = _os.path.join(path, "startup", "bl_app_templates_system", *subdir_args) + if _os.path.isdir(path_test): yield path_test + # Uses default local or system location. + path_test = system_resource('SCRIPTS', path=_os.path.join("startup", "bl_app_templates_system", *subdir_args)) + if path_test and _os.path.isdir(path_test): + yield path_test + def preset_paths(subdir): """ @@ -494,7 +513,7 @@ def preset_paths(subdir): :rtype: list """ dirs = [] - for path in script_paths(subdir="presets", check_all=True): + for path in script_paths(subdir="presets"): directory = _os.path.join(path, subdir) if not directory.startswith(path): raise Exception("invalid subdir given {!r}".format(subdir)) diff --git a/source/blender/blenkernel/intern/appdir.cc b/source/blender/blenkernel/intern/appdir.cc index eb006ffbd06..7b3cd188f0d 100644 --- a/source/blender/blenkernel/intern/appdir.cc +++ b/source/blender/blenkernel/intern/appdir.cc @@ -21,6 +21,7 @@ #include "BLI_string_utils.hh" #include "BLI_tempfile.h" #include "BLI_utildefines.h" +#include "BLI_vector.hh" #include "BKE_appdir.hh" /* own include */ #include "BKE_blender_version.h" @@ -590,10 +591,10 @@ bool BKE_appdir_folder_id_ex(const int folder_id, if (get_path_environment(path, path_maxncpy, subfolder, "BLENDER_SYSTEM_DATAFILES")) { break; } - if (get_path_local(path, path_maxncpy, "datafiles", subfolder)) { + if (get_path_system(path, path_maxncpy, "datafiles", subfolder)) { break; } - if (get_path_system(path, path_maxncpy, "datafiles", subfolder)) { + if (get_path_local(path, path_maxncpy, "datafiles", subfolder)) { break; } return false; @@ -638,9 +639,6 @@ bool BKE_appdir_folder_id_ex(const int folder_id, return false; case BLENDER_SYSTEM_SCRIPTS: - if (get_path_environment(path, path_maxncpy, subfolder, "BLENDER_SYSTEM_SCRIPTS")) { - break; - } if (get_path_system(path, path_maxncpy, "scripts", subfolder)) { break; } @@ -1005,43 +1003,57 @@ bool BKE_appdir_program_python_search(char *program_filepath, /** \name Application Templates * \{ */ -/** Keep in sync with `bpy.utils.app_template_paths()` */ -static const char *app_template_directory_search[2] = { - "startup" SEP_STR "bl_app_templates_user", - "startup" SEP_STR "bl_app_templates_system", -}; +static blender::Vector appdir_app_template_directories() +{ + blender::Vector directories; -static const int app_template_directory_id[2] = { - /* Only 'USER' */ - BLENDER_USER_SCRIPTS, - /* Covers 'LOCAL' & 'SYSTEM'. */ - BLENDER_SYSTEM_SCRIPTS, -}; + /** Keep in sync with `bpy.utils.app_template_paths()` */ + char temp_dir[FILE_MAX]; + if (BKE_appdir_folder_id_ex(BLENDER_USER_SCRIPTS, + "startup" SEP_STR "bl_app_templates_user", + temp_dir, + sizeof(temp_dir))) + { + directories.append(temp_dir); + } + + /* Environment variable. */ + if (get_path_environment(temp_dir, + sizeof(temp_dir), + "startup" SEP_STR "bl_app_templates_system", + "BLENDER_SYSTEM_SCRIPTS")) + { + directories.append(temp_dir); + } + + /* Local or system directory. */ + if (BKE_appdir_folder_id_ex(BLENDER_SYSTEM_SCRIPTS, + "startup" SEP_STR "bl_app_templates_system", + temp_dir, + sizeof(temp_dir))) + { + directories.append(temp_dir); + } + + return directories; +} bool BKE_appdir_app_template_any() { - char temp_dir[FILE_MAX]; - for (int i = 0; i < ARRAY_SIZE(app_template_directory_id); i++) { - if (BKE_appdir_folder_id_ex(app_template_directory_id[i], - app_template_directory_search[i], - temp_dir, - sizeof(temp_dir))) - { - return true; - } - } - return false; + return !appdir_app_template_directories().is_empty(); } bool BKE_appdir_app_template_id_search(const char *app_template, char *path, size_t path_maxncpy) { - for (int i = 0; i < ARRAY_SIZE(app_template_directory_id); i++) { - char subdir[FILE_MAX]; - BLI_path_join(subdir, sizeof(subdir), app_template_directory_search[i], app_template); - if (BKE_appdir_folder_id_ex(app_template_directory_id[i], subdir, path, path_maxncpy)) { + const blender::Vector directories = appdir_app_template_directories(); + + for (const std::string &directory : directories) { + BLI_path_join(path, path_maxncpy, directory.c_str(), app_template); + if (BLI_is_dir(path)) { return true; } } + return false; } @@ -1069,18 +1081,11 @@ void BKE_appdir_app_templates(ListBase *templates) { BLI_listbase_clear(templates); - for (int i = 0; i < ARRAY_SIZE(app_template_directory_id); i++) { - char subdir[FILE_MAX]; - if (!BKE_appdir_folder_id_ex(app_template_directory_id[i], - app_template_directory_search[i], - subdir, - sizeof(subdir))) - { - continue; - } + const blender::Vector directories = appdir_app_template_directories(); + for (const std::string &subdir : directories) { direntry *dirs; - const uint dir_num = BLI_filelist_dir_contents(subdir, &dirs); + const uint dir_num = BLI_filelist_dir_contents(subdir.c_str(), &dirs); for (int f = 0; f < dir_num; f++) { if (!FILENAME_IS_CURRPAR(dirs[f].relname) && S_ISDIR(dirs[f].type)) { char *app_template = BLI_strdup(dirs[f].relname); diff --git a/source/creator/creator_args.cc b/source/creator/creator_args.cc index 67c395e3f65..95dcef1c733 100644 --- a/source/creator/creator_args.cc +++ b/source/creator/creator_args.cc @@ -844,18 +844,17 @@ static void print_help(bArgs *ba, bool all) PRINT("\n"); PRINT("Environment Variables:\n"); - PRINT(" $BLENDER_USER_RESOURCES Top level directory for user files.\n"); - PRINT(" (other 'BLENDER_USER_*' variables override when set).\n"); + PRINT(" $BLENDER_USER_RESOURCES Replace default directory of all user files.\n"); + PRINT(" Other 'BLENDER_USER_*' variables override when set.\n"); PRINT(" $BLENDER_USER_CONFIG Directory for user configuration files.\n"); PRINT(" $BLENDER_USER_SCRIPTS Directory for user scripts.\n"); PRINT(" $BLENDER_USER_EXTENSIONS Directory for user extensions.\n"); PRINT(" $BLENDER_USER_DATAFILES Directory for user data files (icons, translations, ..).\n"); PRINT("\n"); - PRINT(" $BLENDER_SYSTEM_RESOURCES Top level directory for system files.\n"); - PRINT(" (other 'BLENDER_SYSTEM_*' variables override when set).\n"); - PRINT(" $BLENDER_SYSTEM_SCRIPTS Directory for system wide scripts.\n"); - PRINT(" $BLENDER_SYSTEM_DATAFILES Directory for system wide data files.\n"); - PRINT(" $BLENDER_SYSTEM_PYTHON Directory for system Python libraries.\n"); + PRINT(" $BLENDER_SYSTEM_RESOURCES Replace default directory of all bundled resource files.\n"); + PRINT(" $BLENDER_SYSTEM_SCRIPTS Directory to add more bundled scripts.\n"); + PRINT(" $BLENDER_SYSTEM_DATAFILES Directory to replace bundled datafiles.\n"); + PRINT(" $BLENDER_SYSTEM_PYTHON Directory to replace bundled Python libraries.\n"); if (defs.with_ocio) { PRINT(" $OCIO Path to override the OpenColorIO configuration file.\n");